blob: d14b80b14f4307bbcbd0e732ba67efc81aefcd2b [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
njn9f207462009-03-10 22:02:09 +000012 Copyright (C) 2000-2009 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
njnf76d27a2009-05-28 01:53:07 +000095 it safely (ie. it's mapped, and has at least one of the RWX permission bits
96 set). So every N-bit register is shadowed with N V bits, and every memory
97 byte is shadowed with 8 V bits and one A bit.
njn1d0825f2006-03-27 11:37:07 +000098
99 In the implementation, we use two forms of compression (compressed V bits
100 and distinguished secondary maps) to avoid the 9-bit-per-byte overhead
101 for memory.
102
103 Memcheck also tracks extra information about each heap block that is
104 allocated, for detecting memory leaks and other purposes.
105*/
106
107/*------------------------------------------------------------*/
sewardj45d94cc2005-04-20 14:44:11 +0000108/*--- Basic A/V bitmap representation. ---*/
njn25e49d8e72002-09-23 09:36:25 +0000109/*------------------------------------------------------------*/
110
njn1d0825f2006-03-27 11:37:07 +0000111/* All reads and writes are checked against a memory map (a.k.a. shadow
112 memory), which records the state of all memory in the process.
113
114 On 32-bit machines the memory map is organised as follows.
115 The top 16 bits of an address are used to index into a top-level
116 map table, containing 65536 entries. Each entry is a pointer to a
117 second-level map, which records the accesibililty and validity
118 permissions for the 65536 bytes indexed by the lower 16 bits of the
119 address. Each byte is represented by two bits (details are below). So
120 each second-level map contains 16384 bytes. This two-level arrangement
121 conveniently divides the 4G address space into 64k lumps, each size 64k
122 bytes.
123
124 All entries in the primary (top-level) map must point to a valid
125 secondary (second-level) map. Since many of the 64kB chunks will
njndbf7ca72006-03-31 11:57:59 +0000126 have the same status for every bit -- ie. noaccess (for unused
127 address space) or entirely addressable and defined (for code segments) --
128 there are three distinguished secondary maps, which indicate 'noaccess',
129 'undefined' and 'defined'. For these uniform 64kB chunks, the primary
130 map entry points to the relevant distinguished map. In practice,
131 typically more than half of the addressable memory is represented with
132 the 'undefined' or 'defined' distinguished secondary map, so it gives a
133 good saving. It also lets us set the V+A bits of large address regions
134 quickly in set_address_range_perms().
njn1d0825f2006-03-27 11:37:07 +0000135
136 On 64-bit machines it's more complicated. If we followed the same basic
137 scheme we'd have a four-level table which would require too many memory
138 accesses. So instead the top-level map table has 2^19 entries (indexed
139 using bits 16..34 of the address); this covers the bottom 32GB. Any
140 accesses above 32GB are handled with a slow, sparse auxiliary table.
141 Valgrind's address space manager tries very hard to keep things below
142 this 32GB barrier so that performance doesn't suffer too much.
143
144 Note that this file has a lot of different functions for reading and
145 writing shadow memory. Only a couple are strictly necessary (eg.
146 get_vabits2 and set_vabits2), most are just specialised for specific
147 common cases to improve performance.
148
149 Aside: the V+A bits are less precise than they could be -- we have no way
150 of marking memory as read-only. It would be great if we could add an
151 extra state VA_BITSn_READONLY. But then we'd have 5 different states,
152 which requires 2.3 bits to hold, and there's no way to do that elegantly
153 -- we'd have to double up to 4 bits of metadata per byte, which doesn't
154 seem worth it.
155*/
sewardjc859fbf2005-04-22 21:10:28 +0000156
sewardj45d94cc2005-04-20 14:44:11 +0000157/* --------------- Basic configuration --------------- */
sewardj95448072004-11-22 20:19:51 +0000158
sewardj23eb2fd2005-04-22 16:29:19 +0000159/* Only change this. N_PRIMARY_MAP *must* be a power of 2. */
sewardj21f7ff42005-04-28 10:32:02 +0000160
sewardje4ccc012005-05-02 12:53:38 +0000161#if VG_WORDSIZE == 4
sewardj21f7ff42005-04-28 10:32:02 +0000162
163/* cover the entire address space */
164# define N_PRIMARY_BITS 16
165
166#else
167
sewardj34483bc2005-09-28 11:50:20 +0000168/* Just handle the first 32G fast and the rest via auxiliary
sewardj7244e712008-05-02 12:35:48 +0000169 primaries. If you change this, Memcheck will assert at startup.
170 See the definition of UNALIGNED_OR_HIGH for extensive comments. */
sewardj34483bc2005-09-28 11:50:20 +0000171# define N_PRIMARY_BITS 19
sewardj21f7ff42005-04-28 10:32:02 +0000172
173#endif
174
sewardj45d94cc2005-04-20 14:44:11 +0000175
sewardjc1a2cda2005-04-21 17:34:00 +0000176/* Do not change this. */
sewardje4ccc012005-05-02 12:53:38 +0000177#define N_PRIMARY_MAP ( ((UWord)1) << N_PRIMARY_BITS)
sewardjc1a2cda2005-04-21 17:34:00 +0000178
179/* Do not change this. */
sewardj23eb2fd2005-04-22 16:29:19 +0000180#define MAX_PRIMARY_ADDRESS (Addr)((((Addr)65536) * N_PRIMARY_MAP)-1)
181
182
sewardj45d94cc2005-04-20 14:44:11 +0000183/* --------------- Secondary maps --------------- */
njn25e49d8e72002-09-23 09:36:25 +0000184
njn1d0825f2006-03-27 11:37:07 +0000185// Each byte of memory conceptually has an A bit, which indicates its
186// addressability, and 8 V bits, which indicates its definedness.
187//
188// But because very few bytes are partially defined, we can use a nice
189// compression scheme to reduce the size of shadow memory. Each byte of
190// memory has 2 bits which indicates its state (ie. V+A bits):
191//
njndbf7ca72006-03-31 11:57:59 +0000192// 00: noaccess (unaddressable but treated as fully defined)
193// 01: undefined (addressable and fully undefined)
194// 10: defined (addressable and fully defined)
195// 11: partdefined (addressable and partially defined)
njn1d0825f2006-03-27 11:37:07 +0000196//
njndbf7ca72006-03-31 11:57:59 +0000197// In the "partdefined" case, we use a secondary table to store the V bits.
198// Each entry in the secondary-V-bits table maps a byte address to its 8 V
199// bits.
njn1d0825f2006-03-27 11:37:07 +0000200//
201// We store the compressed V+A bits in 8-bit chunks, ie. the V+A bits for
202// four bytes (32 bits) of memory are in each chunk. Hence the name
203// "vabits8". This lets us get the V+A bits for four bytes at a time
204// easily (without having to do any shifting and/or masking), and that is a
205// very common operation. (Note that although each vabits8 chunk
206// is 8 bits in size, it represents 32 bits of memory.)
207//
208// The representation is "inverse" little-endian... each 4 bytes of
209// memory is represented by a 1 byte value, where:
210//
211// - the status of byte (a+0) is held in bits [1..0]
212// - the status of byte (a+1) is held in bits [3..2]
213// - the status of byte (a+2) is held in bits [5..4]
214// - the status of byte (a+3) is held in bits [7..6]
215//
216// It's "inverse" because endianness normally describes a mapping from
217// value bits to memory addresses; in this case the mapping is inverted.
218// Ie. instead of particular value bits being held in certain addresses, in
219// this case certain addresses are represented by particular value bits.
220// See insert_vabits2_into_vabits8() for an example.
221//
222// But note that we don't compress the V bits stored in registers; they
223// need to be explicit to made the shadow operations possible. Therefore
224// when moving values between registers and memory we need to convert
225// between the expanded in-register format and the compressed in-memory
226// format. This isn't so difficult, it just requires careful attention in a
227// few places.
228
229// These represent eight bits of memory.
230#define VA_BITS2_NOACCESS 0x0 // 00b
njndbf7ca72006-03-31 11:57:59 +0000231#define VA_BITS2_UNDEFINED 0x1 // 01b
232#define VA_BITS2_DEFINED 0x2 // 10b
233#define VA_BITS2_PARTDEFINED 0x3 // 11b
njn1d0825f2006-03-27 11:37:07 +0000234
235// These represent 16 bits of memory.
236#define VA_BITS4_NOACCESS 0x0 // 00_00b
njndbf7ca72006-03-31 11:57:59 +0000237#define VA_BITS4_UNDEFINED 0x5 // 01_01b
238#define VA_BITS4_DEFINED 0xa // 10_10b
njn1d0825f2006-03-27 11:37:07 +0000239
240// These represent 32 bits of memory.
241#define VA_BITS8_NOACCESS 0x00 // 00_00_00_00b
njndbf7ca72006-03-31 11:57:59 +0000242#define VA_BITS8_UNDEFINED 0x55 // 01_01_01_01b
243#define VA_BITS8_DEFINED 0xaa // 10_10_10_10b
njn1d0825f2006-03-27 11:37:07 +0000244
245// These represent 64 bits of memory.
246#define VA_BITS16_NOACCESS 0x0000 // 00_00_00_00b x 2
njndbf7ca72006-03-31 11:57:59 +0000247#define VA_BITS16_UNDEFINED 0x5555 // 01_01_01_01b x 2
248#define VA_BITS16_DEFINED 0xaaaa // 10_10_10_10b x 2
njn1d0825f2006-03-27 11:37:07 +0000249
250
251#define SM_CHUNKS 16384
252#define SM_OFF(aaa) (((aaa) & 0xffff) >> 2)
253#define SM_OFF_16(aaa) (((aaa) & 0xffff) >> 3)
254
255// Paranoia: it's critical for performance that the requested inlining
256// occurs. So try extra hard.
257#define INLINE inline __attribute__((always_inline))
258
259static INLINE Addr start_of_this_sm ( Addr a ) {
260 return (a & (~SM_MASK));
261}
262static INLINE Bool is_start_of_sm ( Addr a ) {
263 return (start_of_this_sm(a) == a);
264}
265
njn25e49d8e72002-09-23 09:36:25 +0000266typedef
267 struct {
njn1d0825f2006-03-27 11:37:07 +0000268 UChar vabits8[SM_CHUNKS];
njn25e49d8e72002-09-23 09:36:25 +0000269 }
270 SecMap;
271
njn1d0825f2006-03-27 11:37:07 +0000272// 3 distinguished secondary maps, one for no-access, one for
273// accessible but undefined, and one for accessible and defined.
274// Distinguished secondaries may never be modified.
275#define SM_DIST_NOACCESS 0
njndbf7ca72006-03-31 11:57:59 +0000276#define SM_DIST_UNDEFINED 1
277#define SM_DIST_DEFINED 2
njnb8dca862005-03-14 02:42:44 +0000278
sewardj45d94cc2005-04-20 14:44:11 +0000279static SecMap sm_distinguished[3];
njnb8dca862005-03-14 02:42:44 +0000280
njn1d0825f2006-03-27 11:37:07 +0000281static INLINE Bool is_distinguished_sm ( SecMap* sm ) {
sewardj45d94cc2005-04-20 14:44:11 +0000282 return sm >= &sm_distinguished[0] && sm <= &sm_distinguished[2];
283}
njnb8dca862005-03-14 02:42:44 +0000284
njn1d0825f2006-03-27 11:37:07 +0000285// Forward declaration
286static void update_SM_counts(SecMap* oldSM, SecMap* newSM);
287
sewardj45d94cc2005-04-20 14:44:11 +0000288/* dist_sm points to one of our three distinguished secondaries. Make
289 a copy of it so that we can write to it.
290*/
291static SecMap* copy_for_writing ( SecMap* dist_sm )
292{
293 SecMap* new_sm;
294 tl_assert(dist_sm == &sm_distinguished[0]
njn1d0825f2006-03-27 11:37:07 +0000295 || dist_sm == &sm_distinguished[1]
296 || dist_sm == &sm_distinguished[2]);
njnb8dca862005-03-14 02:42:44 +0000297
sewardj45f4e7c2005-09-27 19:20:21 +0000298 new_sm = VG_(am_shadow_alloc)(sizeof(SecMap));
299 if (new_sm == NULL)
300 VG_(out_of_memory_NORETURN)( "memcheck:allocate new SecMap",
301 sizeof(SecMap) );
sewardj45d94cc2005-04-20 14:44:11 +0000302 VG_(memcpy)(new_sm, dist_sm, sizeof(SecMap));
njn1d0825f2006-03-27 11:37:07 +0000303 update_SM_counts(dist_sm, new_sm);
sewardj45d94cc2005-04-20 14:44:11 +0000304 return new_sm;
305}
njnb8dca862005-03-14 02:42:44 +0000306
njn1d0825f2006-03-27 11:37:07 +0000307/* --------------- Stats --------------- */
308
njndbf7ca72006-03-31 11:57:59 +0000309static Int n_issued_SMs = 0;
310static Int n_deissued_SMs = 0;
311static Int n_noaccess_SMs = N_PRIMARY_MAP; // start with many noaccess DSMs
312static Int n_undefined_SMs = 0;
313static Int n_defined_SMs = 0;
314static Int n_non_DSM_SMs = 0;
315static Int max_noaccess_SMs = 0;
316static Int max_undefined_SMs = 0;
317static Int max_defined_SMs = 0;
318static Int max_non_DSM_SMs = 0;
njn1d0825f2006-03-27 11:37:07 +0000319
sewardj05a46732006-10-17 01:28:10 +0000320/* # searches initiated in auxmap_L1, and # base cmps required */
321static ULong n_auxmap_L1_searches = 0;
322static ULong n_auxmap_L1_cmps = 0;
323/* # of searches that missed in auxmap_L1 and therefore had to
324 be handed to auxmap_L2. And the number of nodes inserted. */
325static ULong n_auxmap_L2_searches = 0;
326static ULong n_auxmap_L2_nodes = 0;
327
njn1d0825f2006-03-27 11:37:07 +0000328static Int n_sanity_cheap = 0;
329static Int n_sanity_expensive = 0;
330
331static Int n_secVBit_nodes = 0;
332static Int max_secVBit_nodes = 0;
333
334static void update_SM_counts(SecMap* oldSM, SecMap* newSM)
335{
njndbf7ca72006-03-31 11:57:59 +0000336 if (oldSM == &sm_distinguished[SM_DIST_NOACCESS ]) n_noaccess_SMs --;
337 else if (oldSM == &sm_distinguished[SM_DIST_UNDEFINED]) n_undefined_SMs--;
338 else if (oldSM == &sm_distinguished[SM_DIST_DEFINED ]) n_defined_SMs --;
339 else { n_non_DSM_SMs --;
340 n_deissued_SMs ++; }
njn1d0825f2006-03-27 11:37:07 +0000341
njndbf7ca72006-03-31 11:57:59 +0000342 if (newSM == &sm_distinguished[SM_DIST_NOACCESS ]) n_noaccess_SMs ++;
343 else if (newSM == &sm_distinguished[SM_DIST_UNDEFINED]) n_undefined_SMs++;
344 else if (newSM == &sm_distinguished[SM_DIST_DEFINED ]) n_defined_SMs ++;
345 else { n_non_DSM_SMs ++;
346 n_issued_SMs ++; }
njn1d0825f2006-03-27 11:37:07 +0000347
njndbf7ca72006-03-31 11:57:59 +0000348 if (n_noaccess_SMs > max_noaccess_SMs ) max_noaccess_SMs = n_noaccess_SMs;
349 if (n_undefined_SMs > max_undefined_SMs) max_undefined_SMs = n_undefined_SMs;
350 if (n_defined_SMs > max_defined_SMs ) max_defined_SMs = n_defined_SMs;
351 if (n_non_DSM_SMs > max_non_DSM_SMs ) max_non_DSM_SMs = n_non_DSM_SMs;
njn1d0825f2006-03-27 11:37:07 +0000352}
sewardj45d94cc2005-04-20 14:44:11 +0000353
354/* --------------- Primary maps --------------- */
355
356/* The main primary map. This covers some initial part of the address
sewardj23eb2fd2005-04-22 16:29:19 +0000357 space, addresses 0 .. (N_PRIMARY_MAP << 16)-1. The rest of it is
sewardj45d94cc2005-04-20 14:44:11 +0000358 handled using the auxiliary primary map.
359*/
sewardj23eb2fd2005-04-22 16:29:19 +0000360static SecMap* primary_map[N_PRIMARY_MAP];
sewardj45d94cc2005-04-20 14:44:11 +0000361
362
363/* An entry in the auxiliary primary map. base must be a 64k-aligned
364 value, and sm points at the relevant secondary map. As with the
365 main primary map, the secondary may be either a real secondary, or
sewardj05a46732006-10-17 01:28:10 +0000366 one of the three distinguished secondaries. DO NOT CHANGE THIS
367 LAYOUT: the first word has to be the key for OSet fast lookups.
sewardj45d94cc2005-04-20 14:44:11 +0000368*/
369typedef
370 struct {
sewardj23eb2fd2005-04-22 16:29:19 +0000371 Addr base;
sewardj45d94cc2005-04-20 14:44:11 +0000372 SecMap* sm;
373 }
374 AuxMapEnt;
375
sewardj05a46732006-10-17 01:28:10 +0000376/* Tunable parameter: How big is the L1 queue? */
377#define N_AUXMAP_L1 24
sewardj45d94cc2005-04-20 14:44:11 +0000378
sewardj05a46732006-10-17 01:28:10 +0000379/* Tunable parameter: How far along the L1 queue to insert
380 entries resulting from L2 lookups? */
381#define AUXMAP_L1_INSERT_IX 12
sewardj45d94cc2005-04-20 14:44:11 +0000382
sewardj05a46732006-10-17 01:28:10 +0000383static struct {
384 Addr base;
385 AuxMapEnt* ent; // pointer to the matching auxmap_L2 node
386 }
387 auxmap_L1[N_AUXMAP_L1];
388
389static OSet* auxmap_L2 = NULL;
390
391static void init_auxmap_L1_L2 ( void )
sewardj45d94cc2005-04-20 14:44:11 +0000392{
sewardj05a46732006-10-17 01:28:10 +0000393 Int i;
394 for (i = 0; i < N_AUXMAP_L1; i++) {
395 auxmap_L1[i].base = 0;
396 auxmap_L1[i].ent = NULL;
sewardj45d94cc2005-04-20 14:44:11 +0000397 }
398
sewardj05a46732006-10-17 01:28:10 +0000399 tl_assert(0 == offsetof(AuxMapEnt,base));
400 tl_assert(sizeof(Addr) == sizeof(void*));
njne2a9ad32007-09-17 05:30:48 +0000401 auxmap_L2 = VG_(OSetGen_Create)( /*keyOff*/ offsetof(AuxMapEnt,base),
402 /*fastCmp*/ NULL,
sewardj9c606bd2008-09-18 18:12:50 +0000403 VG_(malloc), "mc.iaLL.1", VG_(free) );
sewardj05fe85e2005-04-27 22:46:36 +0000404}
405
sewardj05a46732006-10-17 01:28:10 +0000406/* Check representation invariants; if OK return NULL; else a
407 descriptive bit of text. Also return the number of
408 non-distinguished secondary maps referred to from the auxiliary
409 primary maps. */
sewardj05fe85e2005-04-27 22:46:36 +0000410
sewardj05a46732006-10-17 01:28:10 +0000411static HChar* check_auxmap_L1_L2_sanity ( Word* n_secmaps_found )
sewardj05fe85e2005-04-27 22:46:36 +0000412{
sewardj05a46732006-10-17 01:28:10 +0000413 Word i, j;
414 /* On a 32-bit platform, the L2 and L1 tables should
415 both remain empty forever.
sewardj05fe85e2005-04-27 22:46:36 +0000416
sewardj05a46732006-10-17 01:28:10 +0000417 On a 64-bit platform:
418 In the L2 table:
419 all .base & 0xFFFF == 0
420 all .base > MAX_PRIMARY_ADDRESS
421 In the L1 table:
422 all .base & 0xFFFF == 0
423 all (.base > MAX_PRIMARY_ADDRESS
424 .base & 0xFFFF == 0
425 and .ent points to an AuxMapEnt with the same .base)
426 or
427 (.base == 0 and .ent == NULL)
428 */
429 *n_secmaps_found = 0;
430 if (sizeof(void*) == 4) {
431 /* 32-bit platform */
njne2a9ad32007-09-17 05:30:48 +0000432 if (VG_(OSetGen_Size)(auxmap_L2) != 0)
sewardj05a46732006-10-17 01:28:10 +0000433 return "32-bit: auxmap_L2 is non-empty";
434 for (i = 0; i < N_AUXMAP_L1; i++)
435 if (auxmap_L1[i].base != 0 || auxmap_L1[i].ent != NULL)
436 return "32-bit: auxmap_L1 is non-empty";
437 } else {
438 /* 64-bit platform */
439 UWord elems_seen = 0;
440 AuxMapEnt *elem, *res;
441 AuxMapEnt key;
442 /* L2 table */
njne2a9ad32007-09-17 05:30:48 +0000443 VG_(OSetGen_ResetIter)(auxmap_L2);
444 while ( (elem = VG_(OSetGen_Next)(auxmap_L2)) ) {
sewardj05a46732006-10-17 01:28:10 +0000445 elems_seen++;
446 if (0 != (elem->base & (Addr)0xFFFF))
447 return "64-bit: nonzero .base & 0xFFFF in auxmap_L2";
448 if (elem->base <= MAX_PRIMARY_ADDRESS)
449 return "64-bit: .base <= MAX_PRIMARY_ADDRESS in auxmap_L2";
450 if (elem->sm == NULL)
451 return "64-bit: .sm in _L2 is NULL";
452 if (!is_distinguished_sm(elem->sm))
453 (*n_secmaps_found)++;
454 }
455 if (elems_seen != n_auxmap_L2_nodes)
456 return "64-bit: disagreement on number of elems in _L2";
457 /* Check L1-L2 correspondence */
458 for (i = 0; i < N_AUXMAP_L1; i++) {
459 if (auxmap_L1[i].base == 0 && auxmap_L1[i].ent == NULL)
460 continue;
461 if (0 != (auxmap_L1[i].base & (Addr)0xFFFF))
462 return "64-bit: nonzero .base & 0xFFFF in auxmap_L1";
463 if (auxmap_L1[i].base <= MAX_PRIMARY_ADDRESS)
464 return "64-bit: .base <= MAX_PRIMARY_ADDRESS in auxmap_L1";
465 if (auxmap_L1[i].ent == NULL)
466 return "64-bit: .ent is NULL in auxmap_L1";
467 if (auxmap_L1[i].ent->base != auxmap_L1[i].base)
468 return "64-bit: _L1 and _L2 bases are inconsistent";
469 /* Look it up in auxmap_L2. */
470 key.base = auxmap_L1[i].base;
471 key.sm = 0;
njne2a9ad32007-09-17 05:30:48 +0000472 res = VG_(OSetGen_Lookup)(auxmap_L2, &key);
sewardj05a46732006-10-17 01:28:10 +0000473 if (res == NULL)
474 return "64-bit: _L1 .base not found in _L2";
475 if (res != auxmap_L1[i].ent)
476 return "64-bit: _L1 .ent disagrees with _L2 entry";
477 }
478 /* Check L1 contains no duplicates */
479 for (i = 0; i < N_AUXMAP_L1; i++) {
480 if (auxmap_L1[i].base == 0)
481 continue;
482 for (j = i+1; j < N_AUXMAP_L1; j++) {
483 if (auxmap_L1[j].base == 0)
484 continue;
485 if (auxmap_L1[j].base == auxmap_L1[i].base)
486 return "64-bit: duplicate _L1 .base entries";
487 }
488 }
489 }
490 return NULL; /* ok */
491}
492
493static void insert_into_auxmap_L1_at ( Word rank, AuxMapEnt* ent )
494{
495 Word i;
496 tl_assert(ent);
497 tl_assert(rank >= 0 && rank < N_AUXMAP_L1);
498 for (i = N_AUXMAP_L1-1; i > rank; i--)
499 auxmap_L1[i] = auxmap_L1[i-1];
500 auxmap_L1[rank].base = ent->base;
501 auxmap_L1[rank].ent = ent;
502}
503
504static INLINE AuxMapEnt* maybe_find_in_auxmap ( Addr a )
505{
506 AuxMapEnt key;
507 AuxMapEnt* res;
508 Word i;
509
510 tl_assert(a > MAX_PRIMARY_ADDRESS);
511 a &= ~(Addr)0xFFFF;
512
513 /* First search the front-cache, which is a self-organising
514 list containing the most popular entries. */
515
bart5dd8e6a2008-03-22 08:04:29 +0000516 if (LIKELY(auxmap_L1[0].base == a))
sewardj05a46732006-10-17 01:28:10 +0000517 return auxmap_L1[0].ent;
bart5dd8e6a2008-03-22 08:04:29 +0000518 if (LIKELY(auxmap_L1[1].base == a)) {
sewardj05a46732006-10-17 01:28:10 +0000519 Addr t_base = auxmap_L1[0].base;
520 AuxMapEnt* t_ent = auxmap_L1[0].ent;
521 auxmap_L1[0].base = auxmap_L1[1].base;
522 auxmap_L1[0].ent = auxmap_L1[1].ent;
523 auxmap_L1[1].base = t_base;
524 auxmap_L1[1].ent = t_ent;
525 return auxmap_L1[0].ent;
sewardj45d94cc2005-04-20 14:44:11 +0000526 }
527
sewardj05a46732006-10-17 01:28:10 +0000528 n_auxmap_L1_searches++;
sewardj45d94cc2005-04-20 14:44:11 +0000529
sewardj05a46732006-10-17 01:28:10 +0000530 for (i = 0; i < N_AUXMAP_L1; i++) {
531 if (auxmap_L1[i].base == a) {
532 break;
533 }
534 }
535 tl_assert(i >= 0 && i <= N_AUXMAP_L1);
sewardj45d94cc2005-04-20 14:44:11 +0000536
sewardj05a46732006-10-17 01:28:10 +0000537 n_auxmap_L1_cmps += (ULong)(i+1);
sewardj45d94cc2005-04-20 14:44:11 +0000538
sewardj05a46732006-10-17 01:28:10 +0000539 if (i < N_AUXMAP_L1) {
540 if (i > 0) {
541 Addr t_base = auxmap_L1[i-1].base;
542 AuxMapEnt* t_ent = auxmap_L1[i-1].ent;
543 auxmap_L1[i-1].base = auxmap_L1[i-0].base;
544 auxmap_L1[i-1].ent = auxmap_L1[i-0].ent;
545 auxmap_L1[i-0].base = t_base;
546 auxmap_L1[i-0].ent = t_ent;
547 i--;
548 }
549 return auxmap_L1[i].ent;
550 }
551
552 n_auxmap_L2_searches++;
553
554 /* First see if we already have it. */
555 key.base = a;
556 key.sm = 0;
557
njne2a9ad32007-09-17 05:30:48 +0000558 res = VG_(OSetGen_Lookup)(auxmap_L2, &key);
sewardj05a46732006-10-17 01:28:10 +0000559 if (res)
560 insert_into_auxmap_L1_at( AUXMAP_L1_INSERT_IX, res );
561 return res;
562}
563
564static AuxMapEnt* find_or_alloc_in_auxmap ( Addr a )
565{
566 AuxMapEnt *nyu, *res;
567
568 /* First see if we already have it. */
569 res = maybe_find_in_auxmap( a );
bart5dd8e6a2008-03-22 08:04:29 +0000570 if (LIKELY(res))
sewardj05a46732006-10-17 01:28:10 +0000571 return res;
572
573 /* Ok, there's no entry in the secondary map, so we'll have
574 to allocate one. */
575 a &= ~(Addr)0xFFFF;
576
njne2a9ad32007-09-17 05:30:48 +0000577 nyu = (AuxMapEnt*) VG_(OSetGen_AllocNode)( auxmap_L2, sizeof(AuxMapEnt) );
sewardj05a46732006-10-17 01:28:10 +0000578 tl_assert(nyu);
579 nyu->base = a;
580 nyu->sm = &sm_distinguished[SM_DIST_NOACCESS];
njne2a9ad32007-09-17 05:30:48 +0000581 VG_(OSetGen_Insert)( auxmap_L2, nyu );
sewardj05a46732006-10-17 01:28:10 +0000582 insert_into_auxmap_L1_at( AUXMAP_L1_INSERT_IX, nyu );
583 n_auxmap_L2_nodes++;
584 return nyu;
sewardj45d94cc2005-04-20 14:44:11 +0000585}
586
sewardj45d94cc2005-04-20 14:44:11 +0000587/* --------------- SecMap fundamentals --------------- */
588
njn1d0825f2006-03-27 11:37:07 +0000589// In all these, 'low' means it's definitely in the main primary map,
590// 'high' means it's definitely in the auxiliary table.
591
592static INLINE SecMap** get_secmap_low_ptr ( Addr a )
593{
594 UWord pm_off = a >> 16;
595# if VG_DEBUG_MEMORY >= 1
596 tl_assert(pm_off < N_PRIMARY_MAP);
597# endif
598 return &primary_map[ pm_off ];
599}
600
601static INLINE SecMap** get_secmap_high_ptr ( Addr a )
602{
603 AuxMapEnt* am = find_or_alloc_in_auxmap(a);
604 return &am->sm;
605}
606
607static SecMap** get_secmap_ptr ( Addr a )
608{
609 return ( a <= MAX_PRIMARY_ADDRESS
610 ? get_secmap_low_ptr(a)
611 : get_secmap_high_ptr(a));
612}
613
njna7c7ebd2006-03-28 12:51:02 +0000614static INLINE SecMap* get_secmap_for_reading_low ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000615{
616 return *get_secmap_low_ptr(a);
617}
618
njna7c7ebd2006-03-28 12:51:02 +0000619static INLINE SecMap* get_secmap_for_reading_high ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000620{
621 return *get_secmap_high_ptr(a);
622}
623
njna7c7ebd2006-03-28 12:51:02 +0000624static INLINE SecMap* get_secmap_for_writing_low(Addr a)
njn1d0825f2006-03-27 11:37:07 +0000625{
626 SecMap** p = get_secmap_low_ptr(a);
bart5dd8e6a2008-03-22 08:04:29 +0000627 if (UNLIKELY(is_distinguished_sm(*p)))
njn1d0825f2006-03-27 11:37:07 +0000628 *p = copy_for_writing(*p);
629 return *p;
630}
631
njna7c7ebd2006-03-28 12:51:02 +0000632static INLINE SecMap* get_secmap_for_writing_high ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000633{
634 SecMap** p = get_secmap_high_ptr(a);
bart5dd8e6a2008-03-22 08:04:29 +0000635 if (UNLIKELY(is_distinguished_sm(*p)))
njn1d0825f2006-03-27 11:37:07 +0000636 *p = copy_for_writing(*p);
637 return *p;
638}
639
sewardj45d94cc2005-04-20 14:44:11 +0000640/* Produce the secmap for 'a', either from the primary map or by
641 ensuring there is an entry for it in the aux primary map. The
642 secmap may be a distinguished one as the caller will only want to
643 be able to read it.
644*/
sewardj05a46732006-10-17 01:28:10 +0000645static INLINE SecMap* get_secmap_for_reading ( Addr a )
sewardj45d94cc2005-04-20 14:44:11 +0000646{
njn1d0825f2006-03-27 11:37:07 +0000647 return ( a <= MAX_PRIMARY_ADDRESS
njna7c7ebd2006-03-28 12:51:02 +0000648 ? get_secmap_for_reading_low (a)
649 : get_secmap_for_reading_high(a) );
sewardj45d94cc2005-04-20 14:44:11 +0000650}
651
652/* Produce the secmap for 'a', either from the primary map or by
653 ensuring there is an entry for it in the aux primary map. The
654 secmap may not be a distinguished one, since the caller will want
655 to be able to write it. If it is a distinguished secondary, make a
656 writable copy of it, install it, and return the copy instead. (COW
657 semantics).
658*/
njna7c7ebd2006-03-28 12:51:02 +0000659static SecMap* get_secmap_for_writing ( Addr a )
sewardj45d94cc2005-04-20 14:44:11 +0000660{
njn1d0825f2006-03-27 11:37:07 +0000661 return ( a <= MAX_PRIMARY_ADDRESS
njna7c7ebd2006-03-28 12:51:02 +0000662 ? get_secmap_for_writing_low (a)
663 : get_secmap_for_writing_high(a) );
njn1d0825f2006-03-27 11:37:07 +0000664}
665
666/* If 'a' has a SecMap, produce it. Else produce NULL. But don't
667 allocate one if one doesn't already exist. This is used by the
668 leak checker.
669*/
670static SecMap* maybe_get_secmap_for ( Addr a )
671{
sewardj45d94cc2005-04-20 14:44:11 +0000672 if (a <= MAX_PRIMARY_ADDRESS) {
njna7c7ebd2006-03-28 12:51:02 +0000673 return get_secmap_for_reading_low(a);
sewardj45d94cc2005-04-20 14:44:11 +0000674 } else {
njn1d0825f2006-03-27 11:37:07 +0000675 AuxMapEnt* am = maybe_find_in_auxmap(a);
676 return am ? am->sm : NULL;
sewardj45d94cc2005-04-20 14:44:11 +0000677 }
678}
679
njn1d0825f2006-03-27 11:37:07 +0000680/* --------------- Fundamental functions --------------- */
681
682static INLINE
683void insert_vabits2_into_vabits8 ( Addr a, UChar vabits2, UChar* vabits8 )
684{
685 UInt shift = (a & 3) << 1; // shift by 0, 2, 4, or 6
686 *vabits8 &= ~(0x3 << shift); // mask out the two old bits
687 *vabits8 |= (vabits2 << shift); // mask in the two new bits
688}
689
690static INLINE
691void insert_vabits4_into_vabits8 ( Addr a, UChar vabits4, UChar* vabits8 )
692{
693 UInt shift;
694 tl_assert(VG_IS_2_ALIGNED(a)); // Must be 2-aligned
695 shift = (a & 2) << 1; // shift by 0 or 4
696 *vabits8 &= ~(0xf << shift); // mask out the four old bits
697 *vabits8 |= (vabits4 << shift); // mask in the four new bits
698}
699
700static INLINE
701UChar extract_vabits2_from_vabits8 ( Addr a, UChar vabits8 )
702{
703 UInt shift = (a & 3) << 1; // shift by 0, 2, 4, or 6
704 vabits8 >>= shift; // shift the two bits to the bottom
705 return 0x3 & vabits8; // mask out the rest
706}
707
708static INLINE
709UChar extract_vabits4_from_vabits8 ( Addr a, UChar vabits8 )
710{
711 UInt shift;
712 tl_assert(VG_IS_2_ALIGNED(a)); // Must be 2-aligned
713 shift = (a & 2) << 1; // shift by 0 or 4
714 vabits8 >>= shift; // shift the four bits to the bottom
715 return 0xf & vabits8; // mask out the rest
716}
717
718// Note that these four are only used in slow cases. The fast cases do
719// clever things like combine the auxmap check (in
720// get_secmap_{read,writ}able) with alignment checks.
721
722// *** WARNING! ***
723// Any time this function is called, if it is possible that vabits2
njndbf7ca72006-03-31 11:57:59 +0000724// is equal to VA_BITS2_PARTDEFINED, then the corresponding entry in the
njn1d0825f2006-03-27 11:37:07 +0000725// sec-V-bits table must also be set!
726static INLINE
727void set_vabits2 ( Addr a, UChar vabits2 )
728{
njna7c7ebd2006-03-28 12:51:02 +0000729 SecMap* sm = get_secmap_for_writing(a);
njn1d0825f2006-03-27 11:37:07 +0000730 UWord sm_off = SM_OFF(a);
731 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
732}
733
734static INLINE
735UChar get_vabits2 ( Addr a )
736{
njna7c7ebd2006-03-28 12:51:02 +0000737 SecMap* sm = get_secmap_for_reading(a);
njn1d0825f2006-03-27 11:37:07 +0000738 UWord sm_off = SM_OFF(a);
739 UChar vabits8 = sm->vabits8[sm_off];
740 return extract_vabits2_from_vabits8(a, vabits8);
741}
742
sewardjf2184912006-05-03 22:13:57 +0000743// *** WARNING! ***
744// Any time this function is called, if it is possible that any of the
745// 4 2-bit fields in vabits8 are equal to VA_BITS2_PARTDEFINED, then the
746// corresponding entry(s) in the sec-V-bits table must also be set!
747static INLINE
748UChar get_vabits8_for_aligned_word32 ( Addr a )
749{
750 SecMap* sm = get_secmap_for_reading(a);
751 UWord sm_off = SM_OFF(a);
752 UChar vabits8 = sm->vabits8[sm_off];
753 return vabits8;
754}
755
756static INLINE
757void set_vabits8_for_aligned_word32 ( Addr a, UChar vabits8 )
758{
759 SecMap* sm = get_secmap_for_writing(a);
760 UWord sm_off = SM_OFF(a);
761 sm->vabits8[sm_off] = vabits8;
762}
763
764
njn1d0825f2006-03-27 11:37:07 +0000765// Forward declarations
766static UWord get_sec_vbits8(Addr a);
767static void set_sec_vbits8(Addr a, UWord vbits8);
768
769// Returns False if there was an addressability error.
770static INLINE
771Bool set_vbits8 ( Addr a, UChar vbits8 )
772{
773 Bool ok = True;
774 UChar vabits2 = get_vabits2(a);
775 if ( VA_BITS2_NOACCESS != vabits2 ) {
776 // Addressable. Convert in-register format to in-memory format.
777 // Also remove any existing sec V bit entry for the byte if no
778 // longer necessary.
njndbf7ca72006-03-31 11:57:59 +0000779 if ( V_BITS8_DEFINED == vbits8 ) { vabits2 = VA_BITS2_DEFINED; }
780 else if ( V_BITS8_UNDEFINED == vbits8 ) { vabits2 = VA_BITS2_UNDEFINED; }
781 else { vabits2 = VA_BITS2_PARTDEFINED;
njn1d0825f2006-03-27 11:37:07 +0000782 set_sec_vbits8(a, vbits8); }
783 set_vabits2(a, vabits2);
784
785 } else {
786 // Unaddressable! Do nothing -- when writing to unaddressable
787 // memory it acts as a black hole, and the V bits can never be seen
788 // again. So we don't have to write them at all.
789 ok = False;
790 }
791 return ok;
792}
793
794// Returns False if there was an addressability error. In that case, we put
795// all defined bits into vbits8.
796static INLINE
797Bool get_vbits8 ( Addr a, UChar* vbits8 )
798{
799 Bool ok = True;
800 UChar vabits2 = get_vabits2(a);
801
802 // Convert the in-memory format to in-register format.
njndbf7ca72006-03-31 11:57:59 +0000803 if ( VA_BITS2_DEFINED == vabits2 ) { *vbits8 = V_BITS8_DEFINED; }
804 else if ( VA_BITS2_UNDEFINED == vabits2 ) { *vbits8 = V_BITS8_UNDEFINED; }
805 else if ( VA_BITS2_NOACCESS == vabits2 ) {
njn1d0825f2006-03-27 11:37:07 +0000806 *vbits8 = V_BITS8_DEFINED; // Make V bits defined!
807 ok = False;
808 } else {
njndbf7ca72006-03-31 11:57:59 +0000809 tl_assert( VA_BITS2_PARTDEFINED == vabits2 );
njn1d0825f2006-03-27 11:37:07 +0000810 *vbits8 = get_sec_vbits8(a);
811 }
812 return ok;
813}
814
815
816/* --------------- Secondary V bit table ------------ */
817
818// This table holds the full V bit pattern for partially-defined bytes
njndbf7ca72006-03-31 11:57:59 +0000819// (PDBs) that are represented by VA_BITS2_PARTDEFINED in the main shadow
820// memory.
njn1d0825f2006-03-27 11:37:07 +0000821//
822// Note: the nodes in this table can become stale. Eg. if you write a PDB,
823// then overwrite the same address with a fully defined byte, the sec-V-bit
824// node will not necessarily be removed. This is because checking for
825// whether removal is necessary would slow down the fast paths.
826//
827// To avoid the stale nodes building up too much, we periodically (once the
828// table reaches a certain size) garbage collect (GC) the table by
829// traversing it and evicting any "sufficiently stale" nodes, ie. nodes that
830// are stale and haven't been touched for a certain number of collections.
831// If more than a certain proportion of nodes survived, we increase the
832// table size so that GCs occur less often.
833//
834// (So this a bit different to a traditional GC, where you definitely want
835// to remove any dead nodes. It's more like we have a resizable cache and
836// we're trying to find the right balance how many elements to evict and how
837// big to make the cache.)
838//
839// This policy is designed to avoid bad table bloat in the worst case where
840// a program creates huge numbers of stale PDBs -- we would get this bloat
841// if we had no GC -- while handling well the case where a node becomes
842// stale but shortly afterwards is rewritten with a PDB and so becomes
843// non-stale again (which happens quite often, eg. in perf/bz2). If we just
844// remove all stale nodes as soon as possible, we just end up re-adding a
845// lot of them in later again. The "sufficiently stale" approach avoids
846// this. (If a program has many live PDBs, performance will just suck,
847// there's no way around that.)
848
849static OSet* secVBitTable;
850
851// Stats
852static ULong sec_vbits_new_nodes = 0;
853static ULong sec_vbits_updates = 0;
854
855// This must be a power of two; this is checked in mc_pre_clo_init().
856// The size chosen here is a trade-off: if the nodes are bigger (ie. cover
857// a larger address range) they take more space but we can get multiple
858// partially-defined bytes in one if they are close to each other, reducing
859// the number of total nodes. In practice sometimes they are clustered (eg.
860// perf/bz2 repeatedly writes then reads more than 20,000 in a contiguous
861// row), but often not. So we choose something intermediate.
862#define BYTES_PER_SEC_VBIT_NODE 16
863
864// We make the table bigger if more than this many nodes survive a GC.
865#define MAX_SURVIVOR_PROPORTION 0.5
866
867// Each time we make the table bigger, we increase it by this much.
868#define TABLE_GROWTH_FACTOR 2
869
870// This defines "sufficiently stale" -- any node that hasn't been touched in
871// this many GCs will be removed.
872#define MAX_STALE_AGE 2
873
874// We GC the table when it gets this many nodes in it, ie. it's effectively
875// the table size. It can change.
876static Int secVBitLimit = 1024;
877
878// The number of GCs done, used to age sec-V-bit nodes for eviction.
879// Because it's unsigned, wrapping doesn't matter -- the right answer will
880// come out anyway.
881static UInt GCs_done = 0;
882
883typedef
884 struct {
885 Addr a;
886 UChar vbits8[BYTES_PER_SEC_VBIT_NODE];
887 UInt last_touched;
888 }
889 SecVBitNode;
890
891static OSet* createSecVBitTable(void)
892{
njne2a9ad32007-09-17 05:30:48 +0000893 return VG_(OSetGen_Create)( offsetof(SecVBitNode, a),
894 NULL, // use fast comparisons
sewardj9c606bd2008-09-18 18:12:50 +0000895 VG_(malloc), "mc.cSVT.1 (sec VBit table)",
896 VG_(free) );
njn1d0825f2006-03-27 11:37:07 +0000897}
898
899static void gcSecVBitTable(void)
900{
901 OSet* secVBitTable2;
902 SecVBitNode* n;
903 Int i, n_nodes = 0, n_survivors = 0;
904
905 GCs_done++;
906
907 // Create the new table.
908 secVBitTable2 = createSecVBitTable();
909
910 // Traverse the table, moving fresh nodes into the new table.
njne2a9ad32007-09-17 05:30:48 +0000911 VG_(OSetGen_ResetIter)(secVBitTable);
912 while ( (n = VG_(OSetGen_Next)(secVBitTable)) ) {
njn1d0825f2006-03-27 11:37:07 +0000913 Bool keep = False;
914 if ( (GCs_done - n->last_touched) <= MAX_STALE_AGE ) {
915 // Keep node if it's been touched recently enough (regardless of
916 // freshness/staleness).
917 keep = True;
918 } else {
919 // Keep node if any of its bytes are non-stale. Using
920 // get_vabits2() for the lookup is not very efficient, but I don't
921 // think it matters.
922 for (i = 0; i < BYTES_PER_SEC_VBIT_NODE; i++) {
njndbf7ca72006-03-31 11:57:59 +0000923 if (VA_BITS2_PARTDEFINED == get_vabits2(n->a + i)) {
njn1d0825f2006-03-27 11:37:07 +0000924 keep = True; // Found a non-stale byte, so keep
925 break;
926 }
927 }
928 }
929
930 if ( keep ) {
931 // Insert a copy of the node into the new table.
932 SecVBitNode* n2 =
njne2a9ad32007-09-17 05:30:48 +0000933 VG_(OSetGen_AllocNode)(secVBitTable2, sizeof(SecVBitNode));
njn1d0825f2006-03-27 11:37:07 +0000934 *n2 = *n;
njne2a9ad32007-09-17 05:30:48 +0000935 VG_(OSetGen_Insert)(secVBitTable2, n2);
njn1d0825f2006-03-27 11:37:07 +0000936 }
937 }
938
939 // Get the before and after sizes.
njne2a9ad32007-09-17 05:30:48 +0000940 n_nodes = VG_(OSetGen_Size)(secVBitTable);
941 n_survivors = VG_(OSetGen_Size)(secVBitTable2);
njn1d0825f2006-03-27 11:37:07 +0000942
943 // Destroy the old table, and put the new one in its place.
njne2a9ad32007-09-17 05:30:48 +0000944 VG_(OSetGen_Destroy)(secVBitTable);
njn1d0825f2006-03-27 11:37:07 +0000945 secVBitTable = secVBitTable2;
946
947 if (VG_(clo_verbosity) > 1) {
948 Char percbuf[6];
949 VG_(percentify)(n_survivors, n_nodes, 1, 6, percbuf);
sewardj6b523cd2009-07-15 14:49:40 +0000950 VG_(message)(Vg_DebugMsg, "memcheck GC: %d nodes, %d survivors (%s)\n",
njn1d0825f2006-03-27 11:37:07 +0000951 n_nodes, n_survivors, percbuf);
952 }
953
954 // Increase table size if necessary.
955 if (n_survivors > (secVBitLimit * MAX_SURVIVOR_PROPORTION)) {
956 secVBitLimit *= TABLE_GROWTH_FACTOR;
957 if (VG_(clo_verbosity) > 1)
sewardj6b523cd2009-07-15 14:49:40 +0000958 VG_(message)(Vg_DebugMsg, "memcheck GC: increase table size to %d\n",
njn1d0825f2006-03-27 11:37:07 +0000959 secVBitLimit);
960 }
961}
962
963static UWord get_sec_vbits8(Addr a)
964{
965 Addr aAligned = VG_ROUNDDN(a, BYTES_PER_SEC_VBIT_NODE);
966 Int amod = a % BYTES_PER_SEC_VBIT_NODE;
njne2a9ad32007-09-17 05:30:48 +0000967 SecVBitNode* n = VG_(OSetGen_Lookup)(secVBitTable, &aAligned);
njn1d0825f2006-03-27 11:37:07 +0000968 UChar vbits8;
969 tl_assert2(n, "get_sec_vbits8: no node for address %p (%p)\n", aAligned, a);
970 // Shouldn't be fully defined or fully undefined -- those cases shouldn't
971 // make it to the secondary V bits table.
972 vbits8 = n->vbits8[amod];
973 tl_assert(V_BITS8_DEFINED != vbits8 && V_BITS8_UNDEFINED != vbits8);
974 return vbits8;
975}
976
977static void set_sec_vbits8(Addr a, UWord vbits8)
978{
979 Addr aAligned = VG_ROUNDDN(a, BYTES_PER_SEC_VBIT_NODE);
980 Int i, amod = a % BYTES_PER_SEC_VBIT_NODE;
njne2a9ad32007-09-17 05:30:48 +0000981 SecVBitNode* n = VG_(OSetGen_Lookup)(secVBitTable, &aAligned);
njn1d0825f2006-03-27 11:37:07 +0000982 // Shouldn't be fully defined or fully undefined -- those cases shouldn't
983 // make it to the secondary V bits table.
984 tl_assert(V_BITS8_DEFINED != vbits8 && V_BITS8_UNDEFINED != vbits8);
985 if (n) {
986 n->vbits8[amod] = vbits8; // update
987 n->last_touched = GCs_done;
988 sec_vbits_updates++;
989 } else {
990 // New node: assign the specific byte, make the rest invalid (they
991 // should never be read as-is, but be cautious).
njne2a9ad32007-09-17 05:30:48 +0000992 n = VG_(OSetGen_AllocNode)(secVBitTable, sizeof(SecVBitNode));
njn1d0825f2006-03-27 11:37:07 +0000993 n->a = aAligned;
994 for (i = 0; i < BYTES_PER_SEC_VBIT_NODE; i++) {
995 n->vbits8[i] = V_BITS8_UNDEFINED;
996 }
997 n->vbits8[amod] = vbits8;
998 n->last_touched = GCs_done;
999
1000 // Do a table GC if necessary. Nb: do this before inserting the new
1001 // node, to avoid erroneously GC'ing the new node.
njne2a9ad32007-09-17 05:30:48 +00001002 if (secVBitLimit == VG_(OSetGen_Size)(secVBitTable)) {
njn1d0825f2006-03-27 11:37:07 +00001003 gcSecVBitTable();
1004 }
1005
1006 // Insert the new node.
njne2a9ad32007-09-17 05:30:48 +00001007 VG_(OSetGen_Insert)(secVBitTable, n);
njn1d0825f2006-03-27 11:37:07 +00001008 sec_vbits_new_nodes++;
1009
njne2a9ad32007-09-17 05:30:48 +00001010 n_secVBit_nodes = VG_(OSetGen_Size)(secVBitTable);
njn1d0825f2006-03-27 11:37:07 +00001011 if (n_secVBit_nodes > max_secVBit_nodes)
1012 max_secVBit_nodes = n_secVBit_nodes;
1013 }
1014}
sewardj45d94cc2005-04-20 14:44:11 +00001015
1016/* --------------- Endianness helpers --------------- */
1017
1018/* Returns the offset in memory of the byteno-th most significant byte
1019 in a wordszB-sized word, given the specified endianness. */
njn1d0825f2006-03-27 11:37:07 +00001020static INLINE UWord byte_offset_w ( UWord wordszB, Bool bigendian,
sewardj45d94cc2005-04-20 14:44:11 +00001021 UWord byteno ) {
1022 return bigendian ? (wordszB-1-byteno) : byteno;
1023}
1024
sewardj05a46732006-10-17 01:28:10 +00001025
1026/* --------------- Ignored address ranges --------------- */
1027
1028#define M_IGNORE_RANGES 4
1029
1030typedef
1031 struct {
1032 Int used;
1033 Addr start[M_IGNORE_RANGES];
1034 Addr end[M_IGNORE_RANGES];
1035 }
1036 IgnoreRanges;
1037
1038static IgnoreRanges ignoreRanges;
1039
sewardj7ce71662008-05-02 10:33:15 +00001040INLINE Bool MC_(in_ignored_range) ( Addr a )
sewardj05a46732006-10-17 01:28:10 +00001041{
1042 Int i;
bart5dd8e6a2008-03-22 08:04:29 +00001043 if (LIKELY(ignoreRanges.used == 0))
sewardj05a46732006-10-17 01:28:10 +00001044 return False;
1045 for (i = 0; i < ignoreRanges.used; i++) {
1046 if (a >= ignoreRanges.start[i] && a < ignoreRanges.end[i])
1047 return True;
1048 }
1049 return False;
1050}
1051
1052
1053/* Parse a 32- or 64-bit hex number, including leading 0x, from string
1054 starting at *ppc, putting result in *result, and return True. Or
1055 fail, in which case *ppc and *result are undefined, and return
1056 False. */
1057
1058static Bool isHex ( UChar c )
1059{
njn8df80b22009-03-02 05:11:06 +00001060 return ((c >= '0' && c <= '9') ||
1061 (c >= 'a' && c <= 'f') ||
1062 (c >= 'A' && c <= 'F'));
sewardj05a46732006-10-17 01:28:10 +00001063}
1064
1065static UInt fromHex ( UChar c )
1066{
1067 if (c >= '0' && c <= '9')
1068 return (UInt)c - (UInt)'0';
1069 if (c >= 'a' && c <= 'f')
1070 return 10 + (UInt)c - (UInt)'a';
1071 if (c >= 'A' && c <= 'F')
1072 return 10 + (UInt)c - (UInt)'A';
1073 /*NOTREACHED*/
1074 tl_assert(0);
1075 return 0;
1076}
1077
1078static Bool parse_Addr ( UChar** ppc, Addr* result )
1079{
1080 Int used, limit = 2 * sizeof(Addr);
1081 if (**ppc != '0')
1082 return False;
1083 (*ppc)++;
1084 if (**ppc != 'x')
1085 return False;
1086 (*ppc)++;
1087 *result = 0;
1088 used = 0;
1089 while (isHex(**ppc)) {
1090 UInt d = fromHex(**ppc);
1091 tl_assert(d < 16);
1092 *result = ((*result) << 4) | fromHex(**ppc);
1093 (*ppc)++;
1094 used++;
1095 if (used > limit) return False;
1096 }
1097 if (used == 0)
1098 return False;
1099 return True;
1100}
1101
1102/* Parse two such numbers separated by a dash, or fail. */
1103
1104static Bool parse_range ( UChar** ppc, Addr* result1, Addr* result2 )
1105{
1106 Bool ok = parse_Addr(ppc, result1);
1107 if (!ok)
1108 return False;
1109 if (**ppc != '-')
1110 return False;
1111 (*ppc)++;
1112 ok = parse_Addr(ppc, result2);
1113 if (!ok)
1114 return False;
1115 return True;
1116}
1117
1118/* Parse a set of ranges separated by commas into 'ignoreRanges', or
1119 fail. */
1120
1121static Bool parse_ignore_ranges ( UChar* str0 )
1122{
1123 Addr start, end;
1124 Bool ok;
1125 UChar* str = str0;
1126 UChar** ppc = &str;
1127 ignoreRanges.used = 0;
1128 while (1) {
1129 ok = parse_range(ppc, &start, &end);
1130 if (!ok)
1131 return False;
1132 if (ignoreRanges.used >= M_IGNORE_RANGES)
1133 return False;
1134 ignoreRanges.start[ignoreRanges.used] = start;
1135 ignoreRanges.end[ignoreRanges.used] = end;
1136 ignoreRanges.used++;
1137 if (**ppc == 0)
1138 return True;
1139 if (**ppc != ',')
1140 return False;
1141 (*ppc)++;
1142 }
1143 /*NOTREACHED*/
1144 return False;
1145}
1146
1147
sewardj45d94cc2005-04-20 14:44:11 +00001148/* --------------- Load/store slow cases. --------------- */
1149
1150static
njn1d0825f2006-03-27 11:37:07 +00001151#ifndef PERF_FAST_LOADV
1152INLINE
1153#endif
njn45e81252006-03-28 12:35:08 +00001154ULong mc_LOADVn_slow ( Addr a, SizeT nBits, Bool bigendian )
sewardj45d94cc2005-04-20 14:44:11 +00001155{
njn1d0825f2006-03-27 11:37:07 +00001156 /* Make up a 64-bit result V word, which contains the loaded data for
sewardjf3d57dd2005-04-22 20:23:27 +00001157 valid addresses and Defined for invalid addresses. Iterate over
1158 the bytes in the word, from the most significant down to the
1159 least. */
njn1d0825f2006-03-27 11:37:07 +00001160 ULong vbits64 = V_BITS64_UNDEFINED;
njn45e81252006-03-28 12:35:08 +00001161 SizeT szB = nBits / 8;
njn4c245e52009-03-15 23:25:38 +00001162 SSizeT i; // Must be signed.
sewardj45d94cc2005-04-20 14:44:11 +00001163 SizeT n_addrs_bad = 0;
1164 Addr ai;
njn1d0825f2006-03-27 11:37:07 +00001165 Bool partial_load_exemption_applies;
1166 UChar vbits8;
1167 Bool ok;
sewardj45d94cc2005-04-20 14:44:11 +00001168
sewardjc1a2cda2005-04-21 17:34:00 +00001169 PROF_EVENT(30, "mc_LOADVn_slow");
sewardj05a46732006-10-17 01:28:10 +00001170
1171 /* ------------ BEGIN semi-fast cases ------------ */
1172 /* These deal quickly-ish with the common auxiliary primary map
1173 cases on 64-bit platforms. Are merely a speedup hack; can be
1174 omitted without loss of correctness/functionality. Note that in
1175 both cases the "sizeof(void*) == 8" causes these cases to be
1176 folded out by compilers on 32-bit platforms. These are derived
1177 from LOADV64 and LOADV32.
1178 */
bart5dd8e6a2008-03-22 08:04:29 +00001179 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001180 && nBits == 64 && VG_IS_8_ALIGNED(a))) {
1181 SecMap* sm = get_secmap_for_reading(a);
1182 UWord sm_off16 = SM_OFF_16(a);
1183 UWord vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
bart5dd8e6a2008-03-22 08:04:29 +00001184 if (LIKELY(vabits16 == VA_BITS16_DEFINED))
sewardj05a46732006-10-17 01:28:10 +00001185 return V_BITS64_DEFINED;
bart5dd8e6a2008-03-22 08:04:29 +00001186 if (LIKELY(vabits16 == VA_BITS16_UNDEFINED))
sewardj05a46732006-10-17 01:28:10 +00001187 return V_BITS64_UNDEFINED;
1188 /* else fall into the slow case */
1189 }
bart5dd8e6a2008-03-22 08:04:29 +00001190 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001191 && nBits == 32 && VG_IS_4_ALIGNED(a))) {
1192 SecMap* sm = get_secmap_for_reading(a);
1193 UWord sm_off = SM_OFF(a);
1194 UWord vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00001195 if (LIKELY(vabits8 == VA_BITS8_DEFINED))
sewardj05a46732006-10-17 01:28:10 +00001196 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
bart5dd8e6a2008-03-22 08:04:29 +00001197 if (LIKELY(vabits8 == VA_BITS8_UNDEFINED))
sewardj05a46732006-10-17 01:28:10 +00001198 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
1199 /* else fall into slow case */
1200 }
1201 /* ------------ END semi-fast cases ------------ */
1202
njn45e81252006-03-28 12:35:08 +00001203 tl_assert(nBits == 64 || nBits == 32 || nBits == 16 || nBits == 8);
sewardj45d94cc2005-04-20 14:44:11 +00001204
njn1d0825f2006-03-27 11:37:07 +00001205 for (i = szB-1; i >= 0; i--) {
sewardjc1a2cda2005-04-21 17:34:00 +00001206 PROF_EVENT(31, "mc_LOADVn_slow(loop)");
njn45e81252006-03-28 12:35:08 +00001207 ai = a + byte_offset_w(szB, bigendian, i);
njn1d0825f2006-03-27 11:37:07 +00001208 ok = get_vbits8(ai, &vbits8);
1209 if (!ok) n_addrs_bad++;
1210 vbits64 <<= 8;
1211 vbits64 |= vbits8;
sewardj45d94cc2005-04-20 14:44:11 +00001212 }
1213
sewardj0ded7a42005-11-08 02:25:37 +00001214 /* This is a hack which avoids producing errors for code which
1215 insists in stepping along byte strings in aligned word-sized
1216 chunks, and there is a partially defined word at the end. (eg,
1217 optimised strlen). Such code is basically broken at least WRT
1218 semantics of ANSI C, but sometimes users don't have the option
1219 to fix it, and so this option is provided. Note it is now
1220 defaulted to not-engaged.
1221
1222 A load from a partially-addressible place is allowed if:
1223 - the command-line flag is set
1224 - it's a word-sized, word-aligned load
1225 - at least one of the addresses in the word *is* valid
1226 */
1227 partial_load_exemption_applies
njn1d0825f2006-03-27 11:37:07 +00001228 = MC_(clo_partial_loads_ok) && szB == VG_WORDSIZE
sewardj0ded7a42005-11-08 02:25:37 +00001229 && VG_IS_WORD_ALIGNED(a)
1230 && n_addrs_bad < VG_WORDSIZE;
1231
1232 if (n_addrs_bad > 0 && !partial_load_exemption_applies)
sewardj7ce71662008-05-02 10:33:15 +00001233 MC_(record_address_error)( VG_(get_running_tid)(), a, szB, False );
sewardj45d94cc2005-04-20 14:44:11 +00001234
njn1d0825f2006-03-27 11:37:07 +00001235 return vbits64;
sewardj45d94cc2005-04-20 14:44:11 +00001236}
1237
1238
njn1d0825f2006-03-27 11:37:07 +00001239static
1240#ifndef PERF_FAST_STOREV
1241INLINE
1242#endif
njn45e81252006-03-28 12:35:08 +00001243void mc_STOREVn_slow ( Addr a, SizeT nBits, ULong vbytes, Bool bigendian )
sewardj45d94cc2005-04-20 14:44:11 +00001244{
njn45e81252006-03-28 12:35:08 +00001245 SizeT szB = nBits / 8;
njn1d0825f2006-03-27 11:37:07 +00001246 SizeT i, n_addrs_bad = 0;
1247 UChar vbits8;
sewardj45d94cc2005-04-20 14:44:11 +00001248 Addr ai;
njn1d0825f2006-03-27 11:37:07 +00001249 Bool ok;
sewardj45d94cc2005-04-20 14:44:11 +00001250
sewardjc1a2cda2005-04-21 17:34:00 +00001251 PROF_EVENT(35, "mc_STOREVn_slow");
sewardj05a46732006-10-17 01:28:10 +00001252
1253 /* ------------ BEGIN semi-fast cases ------------ */
1254 /* These deal quickly-ish with the common auxiliary primary map
1255 cases on 64-bit platforms. Are merely a speedup hack; can be
1256 omitted without loss of correctness/functionality. Note that in
1257 both cases the "sizeof(void*) == 8" causes these cases to be
1258 folded out by compilers on 32-bit platforms. These are derived
1259 from STOREV64 and STOREV32.
1260 */
bart5dd8e6a2008-03-22 08:04:29 +00001261 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001262 && nBits == 64 && VG_IS_8_ALIGNED(a))) {
1263 SecMap* sm = get_secmap_for_reading(a);
1264 UWord sm_off16 = SM_OFF_16(a);
1265 UWord vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
bart5dd8e6a2008-03-22 08:04:29 +00001266 if (LIKELY( !is_distinguished_sm(sm) &&
sewardj05a46732006-10-17 01:28:10 +00001267 (VA_BITS16_DEFINED == vabits16 ||
1268 VA_BITS16_UNDEFINED == vabits16) )) {
1269 /* Handle common case quickly: a is suitably aligned, */
1270 /* is mapped, and is addressible. */
1271 // Convert full V-bits in register to compact 2-bit form.
bart5dd8e6a2008-03-22 08:04:29 +00001272 if (LIKELY(V_BITS64_DEFINED == vbytes)) {
sewardj05a46732006-10-17 01:28:10 +00001273 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
1274 return;
1275 } else if (V_BITS64_UNDEFINED == vbytes) {
1276 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
1277 return;
1278 }
1279 /* else fall into the slow case */
1280 }
1281 /* else fall into the slow case */
1282 }
bart5dd8e6a2008-03-22 08:04:29 +00001283 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001284 && nBits == 32 && VG_IS_4_ALIGNED(a))) {
1285 SecMap* sm = get_secmap_for_reading(a);
1286 UWord sm_off = SM_OFF(a);
1287 UWord vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00001288 if (LIKELY( !is_distinguished_sm(sm) &&
sewardj05a46732006-10-17 01:28:10 +00001289 (VA_BITS8_DEFINED == vabits8 ||
1290 VA_BITS8_UNDEFINED == vabits8) )) {
1291 /* Handle common case quickly: a is suitably aligned, */
1292 /* is mapped, and is addressible. */
1293 // Convert full V-bits in register to compact 2-bit form.
bart5dd8e6a2008-03-22 08:04:29 +00001294 if (LIKELY(V_BITS32_DEFINED == (vbytes & 0xFFFFFFFF))) {
sewardj05a46732006-10-17 01:28:10 +00001295 sm->vabits8[sm_off] = VA_BITS8_DEFINED;
1296 return;
1297 } else if (V_BITS32_UNDEFINED == (vbytes & 0xFFFFFFFF)) {
1298 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
1299 return;
1300 }
1301 /* else fall into the slow case */
1302 }
1303 /* else fall into the slow case */
1304 }
1305 /* ------------ END semi-fast cases ------------ */
1306
njn45e81252006-03-28 12:35:08 +00001307 tl_assert(nBits == 64 || nBits == 32 || nBits == 16 || nBits == 8);
sewardj45d94cc2005-04-20 14:44:11 +00001308
1309 /* Dump vbytes in memory, iterating from least to most significant
njn718d3b12006-12-16 00:54:12 +00001310 byte. At the same time establish addressibility of the location. */
sewardj45d94cc2005-04-20 14:44:11 +00001311 for (i = 0; i < szB; i++) {
sewardjc1a2cda2005-04-21 17:34:00 +00001312 PROF_EVENT(36, "mc_STOREVn_slow(loop)");
njn45e81252006-03-28 12:35:08 +00001313 ai = a + byte_offset_w(szB, bigendian, i);
njn1d0825f2006-03-27 11:37:07 +00001314 vbits8 = vbytes & 0xff;
1315 ok = set_vbits8(ai, vbits8);
1316 if (!ok) n_addrs_bad++;
sewardj45d94cc2005-04-20 14:44:11 +00001317 vbytes >>= 8;
1318 }
1319
1320 /* If an address error has happened, report it. */
1321 if (n_addrs_bad > 0)
sewardj7ce71662008-05-02 10:33:15 +00001322 MC_(record_address_error)( VG_(get_running_tid)(), a, szB, True );
sewardj45d94cc2005-04-20 14:44:11 +00001323}
1324
1325
njn25e49d8e72002-09-23 09:36:25 +00001326/*------------------------------------------------------------*/
1327/*--- Setting permissions over address ranges. ---*/
1328/*------------------------------------------------------------*/
1329
njn1d0825f2006-03-27 11:37:07 +00001330static void set_address_range_perms ( Addr a, SizeT lenT, UWord vabits16,
1331 UWord dsm_num )
sewardj23eb2fd2005-04-22 16:29:19 +00001332{
njn1d0825f2006-03-27 11:37:07 +00001333 UWord sm_off, sm_off16;
1334 UWord vabits2 = vabits16 & 0x3;
1335 SizeT lenA, lenB, len_to_next_secmap;
1336 Addr aNext;
sewardjae986ca2005-10-12 12:53:20 +00001337 SecMap* sm;
njn1d0825f2006-03-27 11:37:07 +00001338 SecMap** sm_ptr;
sewardjae986ca2005-10-12 12:53:20 +00001339 SecMap* example_dsm;
1340
sewardj23eb2fd2005-04-22 16:29:19 +00001341 PROF_EVENT(150, "set_address_range_perms");
1342
njn1d0825f2006-03-27 11:37:07 +00001343 /* Check the V+A bits make sense. */
njndbf7ca72006-03-31 11:57:59 +00001344 tl_assert(VA_BITS16_NOACCESS == vabits16 ||
1345 VA_BITS16_UNDEFINED == vabits16 ||
1346 VA_BITS16_DEFINED == vabits16);
sewardj23eb2fd2005-04-22 16:29:19 +00001347
njn1d0825f2006-03-27 11:37:07 +00001348 // This code should never write PDBs; ensure this. (See comment above
1349 // set_vabits2().)
njndbf7ca72006-03-31 11:57:59 +00001350 tl_assert(VA_BITS2_PARTDEFINED != vabits2);
njn1d0825f2006-03-27 11:37:07 +00001351
1352 if (lenT == 0)
sewardj23eb2fd2005-04-22 16:29:19 +00001353 return;
1354
njn59973402009-05-20 03:44:09 +00001355 if (lenT > 256 * 1024 * 1024) {
njn1d0825f2006-03-27 11:37:07 +00001356 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
1357 Char* s = "unknown???";
njndbf7ca72006-03-31 11:57:59 +00001358 if (vabits16 == VA_BITS16_NOACCESS ) s = "noaccess";
1359 if (vabits16 == VA_BITS16_UNDEFINED) s = "undefined";
1360 if (vabits16 == VA_BITS16_DEFINED ) s = "defined";
njn1d0825f2006-03-27 11:37:07 +00001361 VG_(message)(Vg_UserMsg, "Warning: set address range perms: "
sewardj6b523cd2009-07-15 14:49:40 +00001362 "large range [0x%lx, 0x%lx) (%s)\n",
tom2a836b52008-07-18 08:38:44 +00001363 a, a + lenT, s);
sewardj23eb2fd2005-04-22 16:29:19 +00001364 }
1365 }
1366
njn1d0825f2006-03-27 11:37:07 +00001367#ifndef PERF_FAST_SARP
sewardj23eb2fd2005-04-22 16:29:19 +00001368 /*------------------ debug-only case ------------------ */
njn1d0825f2006-03-27 11:37:07 +00001369 {
1370 // Endianness doesn't matter here because all bytes are being set to
1371 // the same value.
1372 // Nb: We don't have to worry about updating the sec-V-bits table
1373 // after these set_vabits2() calls because this code never writes
njndbf7ca72006-03-31 11:57:59 +00001374 // VA_BITS2_PARTDEFINED values.
njn1d0825f2006-03-27 11:37:07 +00001375 SizeT i;
1376 for (i = 0; i < lenT; i++) {
1377 set_vabits2(a + i, vabits2);
1378 }
1379 return;
njn25e49d8e72002-09-23 09:36:25 +00001380 }
njn1d0825f2006-03-27 11:37:07 +00001381#endif
sewardj23eb2fd2005-04-22 16:29:19 +00001382
1383 /*------------------ standard handling ------------------ */
sewardj23eb2fd2005-04-22 16:29:19 +00001384
njn1d0825f2006-03-27 11:37:07 +00001385 /* Get the distinguished secondary that we might want
sewardj23eb2fd2005-04-22 16:29:19 +00001386 to use (part of the space-compression scheme). */
njn1d0825f2006-03-27 11:37:07 +00001387 example_dsm = &sm_distinguished[dsm_num];
1388
1389 // We have to handle ranges covering various combinations of partial and
1390 // whole sec-maps. Here is how parts 1, 2 and 3 are used in each case.
1391 // Cases marked with a '*' are common.
1392 //
1393 // TYPE PARTS USED
1394 // ---- ----------
1395 // * one partial sec-map (p) 1
1396 // - one whole sec-map (P) 2
1397 //
1398 // * two partial sec-maps (pp) 1,3
1399 // - one partial, one whole sec-map (pP) 1,2
1400 // - one whole, one partial sec-map (Pp) 2,3
1401 // - two whole sec-maps (PP) 2,2
1402 //
1403 // * one partial, one whole, one partial (pPp) 1,2,3
1404 // - one partial, two whole (pPP) 1,2,2
1405 // - two whole, one partial (PPp) 2,2,3
1406 // - three whole (PPP) 2,2,2
1407 //
1408 // * one partial, N-2 whole, one partial (pP...Pp) 1,2...2,3
1409 // - one partial, N-1 whole (pP...PP) 1,2...2,2
1410 // - N-1 whole, one partial (PP...Pp) 2,2...2,3
1411 // - N whole (PP...PP) 2,2...2,3
1412
1413 // Break up total length (lenT) into two parts: length in the first
1414 // sec-map (lenA), and the rest (lenB); lenT == lenA + lenB.
1415 aNext = start_of_this_sm(a) + SM_SIZE;
1416 len_to_next_secmap = aNext - a;
1417 if ( lenT <= len_to_next_secmap ) {
1418 // Range entirely within one sec-map. Covers almost all cases.
1419 PROF_EVENT(151, "set_address_range_perms-single-secmap");
1420 lenA = lenT;
1421 lenB = 0;
1422 } else if (is_start_of_sm(a)) {
1423 // Range spans at least one whole sec-map, and starts at the beginning
1424 // of a sec-map; skip to Part 2.
1425 PROF_EVENT(152, "set_address_range_perms-startof-secmap");
1426 lenA = 0;
1427 lenB = lenT;
1428 goto part2;
sewardj23eb2fd2005-04-22 16:29:19 +00001429 } else {
njn1d0825f2006-03-27 11:37:07 +00001430 // Range spans two or more sec-maps, first one is partial.
1431 PROF_EVENT(153, "set_address_range_perms-multiple-secmaps");
1432 lenA = len_to_next_secmap;
1433 lenB = lenT - lenA;
1434 }
1435
1436 //------------------------------------------------------------------------
1437 // Part 1: Deal with the first sec_map. Most of the time the range will be
1438 // entirely within a sec_map and this part alone will suffice. Also,
1439 // doing it this way lets us avoid repeatedly testing for the crossing of
1440 // a sec-map boundary within these loops.
1441 //------------------------------------------------------------------------
1442
1443 // If it's distinguished, make it undistinguished if necessary.
1444 sm_ptr = get_secmap_ptr(a);
1445 if (is_distinguished_sm(*sm_ptr)) {
1446 if (*sm_ptr == example_dsm) {
1447 // Sec-map already has the V+A bits that we want, so skip.
1448 PROF_EVENT(154, "set_address_range_perms-dist-sm1-quick");
1449 a = aNext;
1450 lenA = 0;
sewardj23eb2fd2005-04-22 16:29:19 +00001451 } else {
njn1d0825f2006-03-27 11:37:07 +00001452 PROF_EVENT(155, "set_address_range_perms-dist-sm1");
1453 *sm_ptr = copy_for_writing(*sm_ptr);
sewardj23eb2fd2005-04-22 16:29:19 +00001454 }
1455 }
njn1d0825f2006-03-27 11:37:07 +00001456 sm = *sm_ptr;
sewardj23eb2fd2005-04-22 16:29:19 +00001457
njn1d0825f2006-03-27 11:37:07 +00001458 // 1 byte steps
sewardj23eb2fd2005-04-22 16:29:19 +00001459 while (True) {
sewardj23eb2fd2005-04-22 16:29:19 +00001460 if (VG_IS_8_ALIGNED(a)) break;
njn1d0825f2006-03-27 11:37:07 +00001461 if (lenA < 1) break;
1462 PROF_EVENT(156, "set_address_range_perms-loop1a");
1463 sm_off = SM_OFF(a);
1464 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1465 a += 1;
1466 lenA -= 1;
1467 }
1468 // 8-aligned, 8 byte steps
sewardj23eb2fd2005-04-22 16:29:19 +00001469 while (True) {
njn1d0825f2006-03-27 11:37:07 +00001470 if (lenA < 8) break;
1471 PROF_EVENT(157, "set_address_range_perms-loop8a");
1472 sm_off16 = SM_OFF_16(a);
1473 ((UShort*)(sm->vabits8))[sm_off16] = vabits16;
1474 a += 8;
1475 lenA -= 8;
1476 }
1477 // 1 byte steps
1478 while (True) {
1479 if (lenA < 1) break;
1480 PROF_EVENT(158, "set_address_range_perms-loop1b");
1481 sm_off = SM_OFF(a);
1482 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1483 a += 1;
1484 lenA -= 1;
sewardj23eb2fd2005-04-22 16:29:19 +00001485 }
1486
njn1d0825f2006-03-27 11:37:07 +00001487 // We've finished the first sec-map. Is that it?
1488 if (lenB == 0)
sewardj23eb2fd2005-04-22 16:29:19 +00001489 return;
1490
njn1d0825f2006-03-27 11:37:07 +00001491 //------------------------------------------------------------------------
1492 // Part 2: Fast-set entire sec-maps at a time.
1493 //------------------------------------------------------------------------
1494 part2:
1495 // 64KB-aligned, 64KB steps.
1496 // Nb: we can reach here with lenB < SM_SIZE
njn4c245e52009-03-15 23:25:38 +00001497 tl_assert(0 == lenA);
sewardj23eb2fd2005-04-22 16:29:19 +00001498 while (True) {
njn1d0825f2006-03-27 11:37:07 +00001499 if (lenB < SM_SIZE) break;
1500 tl_assert(is_start_of_sm(a));
1501 PROF_EVENT(159, "set_address_range_perms-loop64K");
1502 sm_ptr = get_secmap_ptr(a);
1503 if (!is_distinguished_sm(*sm_ptr)) {
1504 PROF_EVENT(160, "set_address_range_perms-loop64K-free-dist-sm");
1505 // Free the non-distinguished sec-map that we're replacing. This
1506 // case happens moderately often, enough to be worthwhile.
1507 VG_(am_munmap_valgrind)((Addr)*sm_ptr, sizeof(SecMap));
1508 }
1509 update_SM_counts(*sm_ptr, example_dsm);
1510 // Make the sec-map entry point to the example DSM
1511 *sm_ptr = example_dsm;
1512 lenB -= SM_SIZE;
1513 a += SM_SIZE;
1514 }
sewardj23eb2fd2005-04-22 16:29:19 +00001515
njn1d0825f2006-03-27 11:37:07 +00001516 // We've finished the whole sec-maps. Is that it?
1517 if (lenB == 0)
1518 return;
1519
1520 //------------------------------------------------------------------------
1521 // Part 3: Finish off the final partial sec-map, if necessary.
1522 //------------------------------------------------------------------------
1523
1524 tl_assert(is_start_of_sm(a) && lenB < SM_SIZE);
1525
1526 // If it's distinguished, make it undistinguished if necessary.
1527 sm_ptr = get_secmap_ptr(a);
1528 if (is_distinguished_sm(*sm_ptr)) {
1529 if (*sm_ptr == example_dsm) {
1530 // Sec-map already has the V+A bits that we want, so stop.
1531 PROF_EVENT(161, "set_address_range_perms-dist-sm2-quick");
1532 return;
1533 } else {
1534 PROF_EVENT(162, "set_address_range_perms-dist-sm2");
1535 *sm_ptr = copy_for_writing(*sm_ptr);
1536 }
1537 }
1538 sm = *sm_ptr;
1539
1540 // 8-aligned, 8 byte steps
1541 while (True) {
1542 if (lenB < 8) break;
1543 PROF_EVENT(163, "set_address_range_perms-loop8b");
1544 sm_off16 = SM_OFF_16(a);
1545 ((UShort*)(sm->vabits8))[sm_off16] = vabits16;
1546 a += 8;
1547 lenB -= 8;
1548 }
1549 // 1 byte steps
1550 while (True) {
1551 if (lenB < 1) return;
1552 PROF_EVENT(164, "set_address_range_perms-loop1c");
1553 sm_off = SM_OFF(a);
1554 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1555 a += 1;
1556 lenB -= 1;
1557 }
sewardj23eb2fd2005-04-22 16:29:19 +00001558}
sewardj45d94cc2005-04-20 14:44:11 +00001559
sewardjc859fbf2005-04-22 21:10:28 +00001560
1561/* --- Set permissions for arbitrary address ranges --- */
njn25e49d8e72002-09-23 09:36:25 +00001562
njndbf7ca72006-03-31 11:57:59 +00001563void MC_(make_mem_noaccess) ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001564{
njndbf7ca72006-03-31 11:57:59 +00001565 PROF_EVENT(40, "MC_(make_mem_noaccess)");
1566 DEBUG("MC_(make_mem_noaccess)(%p, %lu)\n", a, len);
njn1d0825f2006-03-27 11:37:07 +00001567 set_address_range_perms ( a, len, VA_BITS16_NOACCESS, SM_DIST_NOACCESS );
sewardj7cf4e6b2008-05-01 20:24:26 +00001568 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1569 ocache_sarp_Clear_Origins ( a, len );
njn25e49d8e72002-09-23 09:36:25 +00001570}
1571
sewardj7cf4e6b2008-05-01 20:24:26 +00001572static void make_mem_undefined ( Addr a, SizeT len )
1573{
1574 PROF_EVENT(41, "make_mem_undefined");
1575 DEBUG("make_mem_undefined(%p, %lu)\n", a, len);
1576 set_address_range_perms ( a, len, VA_BITS16_UNDEFINED, SM_DIST_UNDEFINED );
1577}
1578
1579void MC_(make_mem_undefined_w_otag) ( Addr a, SizeT len, UInt otag )
njn25e49d8e72002-09-23 09:36:25 +00001580{
njndbf7ca72006-03-31 11:57:59 +00001581 PROF_EVENT(41, "MC_(make_mem_undefined)");
1582 DEBUG("MC_(make_mem_undefined)(%p, %lu)\n", a, len);
1583 set_address_range_perms ( a, len, VA_BITS16_UNDEFINED, SM_DIST_UNDEFINED );
sewardj7cf4e6b2008-05-01 20:24:26 +00001584 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1585 ocache_sarp_Set_Origins ( a, len, otag );
njn25e49d8e72002-09-23 09:36:25 +00001586}
1587
sewardj7cf4e6b2008-05-01 20:24:26 +00001588static
1589void make_mem_undefined_w_tid_and_okind ( Addr a, SizeT len,
1590 ThreadId tid, UInt okind )
1591{
1592 UInt ecu;
1593 ExeContext* here;
1594 /* VG_(record_ExeContext) checks for validity of tid, and asserts
1595 if it is invalid. So no need to do it here. */
1596 tl_assert(okind <= 3);
1597 here = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ );
1598 tl_assert(here);
1599 ecu = VG_(get_ECU_from_ExeContext)(here);
1600 tl_assert(VG_(is_plausible_ECU)(ecu));
1601 MC_(make_mem_undefined_w_otag) ( a, len, ecu | okind );
1602}
1603
1604static
1605void make_mem_undefined_w_tid ( Addr a, SizeT len, ThreadId tid ) {
1606 make_mem_undefined_w_tid_and_okind ( a, len, tid, MC_OKIND_UNKNOWN );
1607}
1608
1609
njndbf7ca72006-03-31 11:57:59 +00001610void MC_(make_mem_defined) ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001611{
njndbf7ca72006-03-31 11:57:59 +00001612 PROF_EVENT(42, "MC_(make_mem_defined)");
1613 DEBUG("MC_(make_mem_defined)(%p, %lu)\n", a, len);
1614 set_address_range_perms ( a, len, VA_BITS16_DEFINED, SM_DIST_DEFINED );
sewardj7cf4e6b2008-05-01 20:24:26 +00001615 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1616 ocache_sarp_Clear_Origins ( a, len );
njn25e49d8e72002-09-23 09:36:25 +00001617}
1618
sewardjfb1e9ad2006-03-10 13:41:58 +00001619/* For each byte in [a,a+len), if the byte is addressable, make it be
1620 defined, but if it isn't addressible, leave it alone. In other
njndbf7ca72006-03-31 11:57:59 +00001621 words a version of MC_(make_mem_defined) that doesn't mess with
sewardjfb1e9ad2006-03-10 13:41:58 +00001622 addressibility. Low-performance implementation. */
njndbf7ca72006-03-31 11:57:59 +00001623static void make_mem_defined_if_addressable ( Addr a, SizeT len )
sewardjfb1e9ad2006-03-10 13:41:58 +00001624{
1625 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00001626 UChar vabits2;
njndbf7ca72006-03-31 11:57:59 +00001627 DEBUG("make_mem_defined_if_addressable(%p, %llu)\n", a, (ULong)len);
sewardjfb1e9ad2006-03-10 13:41:58 +00001628 for (i = 0; i < len; i++) {
njn1d0825f2006-03-27 11:37:07 +00001629 vabits2 = get_vabits2( a+i );
bart5dd8e6a2008-03-22 08:04:29 +00001630 if (LIKELY(VA_BITS2_NOACCESS != vabits2)) {
njndbf7ca72006-03-31 11:57:59 +00001631 set_vabits2(a+i, VA_BITS2_DEFINED);
sewardj7cf4e6b2008-05-01 20:24:26 +00001632 if (UNLIKELY(MC_(clo_mc_level) >= 3)) {
1633 MC_(helperc_b_store1)( a+i, 0 ); /* clear the origin tag */
1634 }
njn1d0825f2006-03-27 11:37:07 +00001635 }
sewardjfb1e9ad2006-03-10 13:41:58 +00001636 }
1637}
1638
njn9b007f62003-04-07 14:40:25 +00001639
sewardj45f4e7c2005-09-27 19:20:21 +00001640/* --- Block-copy permissions (needed for implementing realloc() and
1641 sys_mremap). --- */
sewardjc859fbf2005-04-22 21:10:28 +00001642
njn1d0825f2006-03-27 11:37:07 +00001643void MC_(copy_address_range_state) ( Addr src, Addr dst, SizeT len )
sewardjc859fbf2005-04-22 21:10:28 +00001644{
sewardj45f4e7c2005-09-27 19:20:21 +00001645 SizeT i, j;
sewardjf2184912006-05-03 22:13:57 +00001646 UChar vabits2, vabits8;
1647 Bool aligned, nooverlap;
sewardjc859fbf2005-04-22 21:10:28 +00001648
njn1d0825f2006-03-27 11:37:07 +00001649 DEBUG("MC_(copy_address_range_state)\n");
1650 PROF_EVENT(50, "MC_(copy_address_range_state)");
sewardj45f4e7c2005-09-27 19:20:21 +00001651
sewardjf2184912006-05-03 22:13:57 +00001652 if (len == 0 || src == dst)
sewardj45f4e7c2005-09-27 19:20:21 +00001653 return;
1654
sewardjf2184912006-05-03 22:13:57 +00001655 aligned = VG_IS_4_ALIGNED(src) && VG_IS_4_ALIGNED(dst);
1656 nooverlap = src+len <= dst || dst+len <= src;
sewardj45f4e7c2005-09-27 19:20:21 +00001657
sewardjf2184912006-05-03 22:13:57 +00001658 if (nooverlap && aligned) {
1659
1660 /* Vectorised fast case, when no overlap and suitably aligned */
1661 /* vector loop */
1662 i = 0;
1663 while (len >= 4) {
1664 vabits8 = get_vabits8_for_aligned_word32( src+i );
1665 set_vabits8_for_aligned_word32( dst+i, vabits8 );
bart5dd8e6a2008-03-22 08:04:29 +00001666 if (LIKELY(VA_BITS8_DEFINED == vabits8
sewardjf2184912006-05-03 22:13:57 +00001667 || VA_BITS8_UNDEFINED == vabits8
1668 || VA_BITS8_NOACCESS == vabits8)) {
1669 /* do nothing */
1670 } else {
1671 /* have to copy secondary map info */
1672 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+0 ))
1673 set_sec_vbits8( dst+i+0, get_sec_vbits8( src+i+0 ) );
1674 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+1 ))
1675 set_sec_vbits8( dst+i+1, get_sec_vbits8( src+i+1 ) );
1676 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+2 ))
1677 set_sec_vbits8( dst+i+2, get_sec_vbits8( src+i+2 ) );
1678 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+3 ))
1679 set_sec_vbits8( dst+i+3, get_sec_vbits8( src+i+3 ) );
1680 }
1681 i += 4;
1682 len -= 4;
1683 }
1684 /* fixup loop */
1685 while (len >= 1) {
njn1d0825f2006-03-27 11:37:07 +00001686 vabits2 = get_vabits2( src+i );
1687 set_vabits2( dst+i, vabits2 );
njndbf7ca72006-03-31 11:57:59 +00001688 if (VA_BITS2_PARTDEFINED == vabits2) {
njn1d0825f2006-03-27 11:37:07 +00001689 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1690 }
sewardjf2184912006-05-03 22:13:57 +00001691 i++;
1692 len--;
1693 }
1694
1695 } else {
1696
1697 /* We have to do things the slow way */
1698 if (src < dst) {
1699 for (i = 0, j = len-1; i < len; i++, j--) {
1700 PROF_EVENT(51, "MC_(copy_address_range_state)(loop)");
1701 vabits2 = get_vabits2( src+j );
1702 set_vabits2( dst+j, vabits2 );
1703 if (VA_BITS2_PARTDEFINED == vabits2) {
1704 set_sec_vbits8( dst+j, get_sec_vbits8( src+j ) );
1705 }
1706 }
1707 }
1708
1709 if (src > dst) {
1710 for (i = 0; i < len; i++) {
1711 PROF_EVENT(52, "MC_(copy_address_range_state)(loop)");
1712 vabits2 = get_vabits2( src+i );
1713 set_vabits2( dst+i, vabits2 );
1714 if (VA_BITS2_PARTDEFINED == vabits2) {
1715 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1716 }
1717 }
sewardj45f4e7c2005-09-27 19:20:21 +00001718 }
sewardjc859fbf2005-04-22 21:10:28 +00001719 }
sewardjf2184912006-05-03 22:13:57 +00001720
sewardjc859fbf2005-04-22 21:10:28 +00001721}
1722
1723
sewardj7cf4e6b2008-05-01 20:24:26 +00001724/*------------------------------------------------------------*/
1725/*--- Origin tracking stuff - cache basics ---*/
1726/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00001727
sewardj77139802008-05-05 09:48:56 +00001728/* AN OVERVIEW OF THE ORIGIN TRACKING IMPLEMENTATION
1729 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sewardj7cf4e6b2008-05-01 20:24:26 +00001730
1731 Note that this implementation draws inspiration from the "origin
1732 tracking by value piggybacking" scheme described in "Tracking Bad
1733 Apples: Reporting the Origin of Null and Undefined Value Errors"
1734 (Michael Bond, Nicholas Nethercote, Stephen Kent, Samuel Guyer,
1735 Kathryn McKinley, OOPSLA07, Montreal, Oct 2007) but in fact it is
1736 implemented completely differently.
1737
sewardj77139802008-05-05 09:48:56 +00001738 Origin tags and ECUs -- about the shadow values
1739 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1740
1741 This implementation tracks the defining point of all uninitialised
1742 values using so called "origin tags", which are 32-bit integers,
1743 rather than using the values themselves to encode the origins. The
1744 latter, so-called value piggybacking", is what the OOPSLA07 paper
sewardj7cf4e6b2008-05-01 20:24:26 +00001745 describes.
1746
1747 Origin tags, as tracked by the machinery below, are 32-bit unsigned
sewardj77139802008-05-05 09:48:56 +00001748 ints (UInts), regardless of the machine's word size. Each tag
1749 comprises an upper 30-bit ECU field and a lower 2-bit
1750 'kind' field. The ECU field is a number given out by m_execontext
1751 and has a 1-1 mapping with ExeContext*s. An ECU can be used
1752 directly as an origin tag (otag), but in fact we want to put
1753 additional information 'kind' field to indicate roughly where the
1754 tag came from. This helps print more understandable error messages
1755 for the user -- it has no other purpose. In summary:
1756
1757 * Both ECUs and origin tags are represented as 32-bit words
1758
1759 * m_execontext and the core-tool interface deal purely in ECUs.
1760 They have no knowledge of origin tags - that is a purely
1761 Memcheck-internal matter.
1762
1763 * all valid ECUs have the lowest 2 bits zero and at least
1764 one of the upper 30 bits nonzero (see VG_(is_plausible_ECU))
1765
1766 * to convert from an ECU to an otag, OR in one of the MC_OKIND_
1767 constants defined in mc_include.h.
1768
1769 * to convert an otag back to an ECU, AND it with ~3
1770
1771 One important fact is that no valid otag is zero. A zero otag is
1772 used by the implementation to indicate "no origin", which could
1773 mean that either the value is defined, or it is undefined but the
1774 implementation somehow managed to lose the origin.
1775
1776 The ECU used for memory created by malloc etc is derived from the
1777 stack trace at the time the malloc etc happens. This means the
1778 mechanism can show the exact allocation point for heap-created
1779 uninitialised values.
1780
1781 In contrast, it is simply too expensive to create a complete
1782 backtrace for each stack allocation. Therefore we merely use a
1783 depth-1 backtrace for stack allocations, which can be done once at
1784 translation time, rather than N times at run time. The result of
1785 this is that, for stack created uninitialised values, Memcheck can
1786 only show the allocating function, and not what called it.
1787 Furthermore, compilers tend to move the stack pointer just once at
1788 the start of the function, to allocate all locals, and so in fact
1789 the stack origin almost always simply points to the opening brace
1790 of the function. Net result is, for stack origins, the mechanism
1791 can tell you in which function the undefined value was created, but
1792 that's all. Users will need to carefully check all locals in the
1793 specified function.
1794
1795 Shadowing registers and memory
1796 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1797
1798 Memory is shadowed using a two level cache structure (ocacheL1 and
1799 ocacheL2). Memory references are first directed to ocacheL1. This
1800 is a traditional 2-way set associative cache with 32-byte lines and
1801 approximate LRU replacement within each set.
1802
1803 A naive implementation would require storing one 32 bit otag for
1804 each byte of memory covered, a 4:1 space overhead. Instead, there
1805 is one otag for every 4 bytes of memory covered, plus a 4-bit mask
1806 that shows which of the 4 bytes have that shadow value and which
1807 have a shadow value of zero (indicating no origin). Hence a lot of
1808 space is saved, but the cost is that only one different origin per
1809 4 bytes of address space can be represented. This is a source of
1810 imprecision, but how much of a problem it really is remains to be
1811 seen.
1812
1813 A cache line that contains all zeroes ("no origins") contains no
1814 useful information, and can be ejected from the L1 cache "for
1815 free", in the sense that a read miss on the L1 causes a line of
1816 zeroes to be installed. However, ejecting a line containing
1817 nonzeroes risks losing origin information permanently. In order to
1818 prevent such lossage, ejected nonzero lines are placed in a
1819 secondary cache (ocacheL2), which is an OSet (AVL tree) of cache
1820 lines. This can grow arbitrarily large, and so should ensure that
1821 Memcheck runs out of memory in preference to losing useful origin
1822 info due to cache size limitations.
1823
1824 Shadowing registers is a bit tricky, because the shadow values are
1825 32 bits, regardless of the size of the register. That gives a
1826 problem for registers smaller than 32 bits. The solution is to
1827 find spaces in the guest state that are unused, and use those to
1828 shadow guest state fragments smaller than 32 bits. For example, on
1829 ppc32/64, each vector register is 16 bytes long. If 4 bytes of the
1830 shadow are allocated for the register's otag, then there are still
1831 12 bytes left over which could be used to shadow 3 other values.
1832
1833 This implies there is some non-obvious mapping from guest state
1834 (start,length) pairs to the relevant shadow offset (for the origin
1835 tags). And it is unfortunately guest-architecture specific. The
1836 mapping is contained in mc_machine.c, which is quite lengthy but
1837 straightforward.
1838
1839 Instrumenting the IR
1840 ~~~~~~~~~~~~~~~~~~~~
1841
1842 Instrumentation is largely straightforward, and done by the
1843 functions schemeE and schemeS in mc_translate.c. These generate
1844 code for handling the origin tags of expressions (E) and statements
1845 (S) respectively. The rather strange names are a reference to the
1846 "compilation schemes" shown in Simon Peyton Jones' book "The
1847 Implementation of Functional Programming Languages" (Prentice Hall,
1848 1987, see
1849 http://research.microsoft.com/~simonpj/papers/slpj-book-1987/index.htm).
1850
1851 schemeS merely arranges to move shadow values around the guest
1852 state to track the incoming IR. schemeE is largely trivial too.
1853 The only significant point is how to compute the otag corresponding
1854 to binary (or ternary, quaternary, etc) operator applications. The
1855 rule is simple: just take whichever value is larger (32-bit
1856 unsigned max). Constants get the special value zero. Hence this
1857 rule always propagates a nonzero (known) otag in preference to a
1858 zero (unknown, or more likely, value-is-defined) tag, as we want.
1859 If two different undefined values are inputs to a binary operator
1860 application, then which is propagated is arbitrary, but that
1861 doesn't matter, since the program is erroneous in using either of
1862 the values, and so there's no point in attempting to propagate
1863 both.
1864
1865 Since constants are abstracted to (otag) zero, much of the
1866 instrumentation code can be folded out without difficulty by the
1867 generic post-instrumentation IR cleanup pass, using these rules:
1868 Max32U(0,x) -> x, Max32U(x,0) -> x, Max32(x,y) where x and y are
1869 constants is evaluated at JIT time. And the resulting dead code
1870 removal. In practice this causes surprisingly few Max32Us to
1871 survive through to backend code generation.
1872
1873 Integration with the V-bits machinery
1874 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1875
1876 This is again largely straightforward. Mostly the otag and V bits
1877 stuff are independent. The only point of interaction is when the V
1878 bits instrumenter creates a call to a helper function to report an
1879 uninitialised value error -- in that case it must first use schemeE
1880 to get hold of the origin tag expression for the value, and pass
1881 that to the helper too.
1882
1883 There is the usual stuff to do with setting address range
1884 permissions. When memory is painted undefined, we must also know
1885 the origin tag to paint with, which involves some tedious plumbing,
1886 particularly to do with the fast case stack handlers. When memory
1887 is painted defined or noaccess then the origin tags must be forced
1888 to zero.
1889
1890 One of the goals of the implementation was to ensure that the
1891 non-origin tracking mode isn't slowed down at all. To do this,
1892 various functions to do with memory permissions setting (again,
1893 mostly pertaining to the stack) are duplicated for the with- and
1894 without-otag case.
1895
1896 Dealing with stack redzones, and the NIA cache
1897 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1898
1899 This is one of the few non-obvious parts of the implementation.
1900
1901 Some ABIs (amd64-ELF, ppc64-ELF, ppc32/64-XCOFF) define a small
1902 reserved area below the stack pointer, that can be used as scratch
1903 space by compiler generated code for functions. In the Memcheck
1904 sources this is referred to as the "stack redzone". The important
1905 thing here is that such redzones are considered volatile across
1906 function calls and returns. So Memcheck takes care to mark them as
1907 undefined for each call and return, on the afflicted platforms.
1908 Past experience shows this is essential in order to get reliable
1909 messages about uninitialised values that come from the stack.
1910
1911 So the question is, when we paint a redzone undefined, what origin
1912 tag should we use for it? Consider a function f() calling g(). If
1913 we paint the redzone using an otag derived from the ExeContext of
1914 the CALL/BL instruction in f, then any errors in g causing it to
1915 use uninitialised values that happen to lie in the redzone, will be
1916 reported as having their origin in f. Which is highly confusing.
1917
1918 The same applies for returns: if, on a return, we paint the redzone
1919 using a origin tag derived from the ExeContext of the RET/BLR
1920 instruction in g, then any later errors in f causing it to use
1921 uninitialised values in the redzone, will be reported as having
1922 their origin in g. Which is just as confusing.
1923
1924 To do it right, in both cases we need to use an origin tag which
1925 pertains to the instruction which dynamically follows the CALL/BL
1926 or RET/BLR. In short, one derived from the NIA - the "next
1927 instruction address".
1928
1929 To make this work, Memcheck's redzone-painting helper,
1930 MC_(helperc_MAKE_STACK_UNINIT), now takes a third argument, the
1931 NIA. It converts the NIA to a 1-element ExeContext, and uses that
1932 ExeContext's ECU as the basis for the otag used to paint the
1933 redzone. The expensive part of this is converting an NIA into an
1934 ECU, since this happens once for every call and every return. So
1935 we use a simple 511-line, 2-way set associative cache
1936 (nia_to_ecu_cache) to cache the mappings, and that knocks most of
1937 the cost out.
1938
1939 Further background comments
1940 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
sewardj7cf4e6b2008-05-01 20:24:26 +00001941
1942 > Question: why is otag a UInt? Wouldn't a UWord be better? Isn't
1943 > it really just the address of the relevant ExeContext?
1944
1945 Well, it's not the address, but a value which has a 1-1 mapping
1946 with ExeContexts, and is guaranteed not to be zero, since zero
1947 denotes (to memcheck) "unknown origin or defined value". So these
sewardj77139802008-05-05 09:48:56 +00001948 UInts are just numbers starting at 4 and incrementing by 4; each
1949 ExeContext is given a number when it is created. (*** NOTE this
1950 confuses otags and ECUs; see comments above ***).
sewardj7cf4e6b2008-05-01 20:24:26 +00001951
1952 Making these otags 32-bit regardless of the machine's word size
1953 makes the 64-bit implementation easier (next para). And it doesn't
1954 really limit us in any way, since for the tags to overflow would
sewardj77139802008-05-05 09:48:56 +00001955 require that the program somehow caused 2^30-1 different
sewardj7cf4e6b2008-05-01 20:24:26 +00001956 ExeContexts to be created, in which case it is probably in deep
1957 trouble. Not to mention V will have soaked up many tens of
1958 gigabytes of memory merely to store them all.
1959
1960 So having 64-bit origins doesn't really buy you anything, and has
1961 the following downsides:
1962
1963 Suppose that instead, an otag is a UWord. This would mean that, on
1964 a 64-bit target,
1965
1966 1. It becomes hard to shadow any element of guest state which is
1967 smaller than 8 bytes. To do so means you'd need to find some
1968 8-byte-sized hole in the guest state which you don't want to
1969 shadow, and use that instead to hold the otag. On ppc64, the
1970 condition code register(s) are split into 20 UChar sized pieces,
1971 all of which need to be tracked (guest_XER_SO .. guest_CR7_0)
1972 and so that would entail finding 160 bytes somewhere else in the
1973 guest state.
1974
1975 Even on x86, I want to track origins for %AH .. %DH (bits 15:8
1976 of %EAX .. %EDX) that are separate from %AL .. %DL (bits 7:0 of
1977 same) and so I had to look for 4 untracked otag-sized areas in
1978 the guest state to make that possible.
1979
1980 The same problem exists of course when origin tags are only 32
1981 bits, but it's less extreme.
1982
1983 2. (More compelling) it doubles the size of the origin shadow
1984 memory. Given that the shadow memory is organised as a fixed
1985 size cache, and that accuracy of tracking is limited by origins
1986 falling out the cache due to space conflicts, this isn't good.
1987
1988 > Another question: is the origin tracking perfect, or are there
1989 > cases where it fails to determine an origin?
1990
1991 It is imperfect for at least for the following reasons, and
1992 probably more:
1993
1994 * Insufficient capacity in the origin cache. When a line is
1995 evicted from the cache it is gone forever, and so subsequent
1996 queries for the line produce zero, indicating no origin
1997 information. Interestingly, a line containing all zeroes can be
1998 evicted "free" from the cache, since it contains no useful
1999 information, so there is scope perhaps for some cleverer cache
sewardj77139802008-05-05 09:48:56 +00002000 management schemes. (*** NOTE, with the introduction of the
2001 second level origin tag cache, ocacheL2, this is no longer a
2002 problem. ***)
sewardj7cf4e6b2008-05-01 20:24:26 +00002003
2004 * The origin cache only stores one otag per 32-bits of address
2005 space, plus 4 bits indicating which of the 4 bytes has that tag
2006 and which are considered defined. The result is that if two
2007 undefined bytes in the same word are stored in memory, the first
2008 stored byte's origin will be lost and replaced by the origin for
2009 the second byte.
2010
2011 * Nonzero origin tags for defined values. Consider a binary
2012 operator application op(x,y). Suppose y is undefined (and so has
2013 a valid nonzero origin tag), and x is defined, but erroneously
2014 has a nonzero origin tag (defined values should have tag zero).
2015 If the erroneous tag has a numeric value greater than y's tag,
2016 then the rule for propagating origin tags though binary
2017 operations, which is simply to take the unsigned max of the two
2018 tags, will erroneously propagate x's tag rather than y's.
2019
2020 * Some obscure uses of x86/amd64 byte registers can cause lossage
2021 or confusion of origins. %AH .. %DH are treated as different
2022 from, and unrelated to, their parent registers, %EAX .. %EDX.
2023 So some wierd sequences like
2024
2025 movb undefined-value, %AH
2026 movb defined-value, %AL
2027 .. use %AX or %EAX ..
2028
2029 will cause the origin attributed to %AH to be ignored, since %AL,
2030 %AX, %EAX are treated as the same register, and %AH as a
2031 completely separate one.
2032
2033 But having said all that, it actually seems to work fairly well in
2034 practice.
2035*/
2036
2037static UWord stats_ocacheL1_find = 0;
2038static UWord stats_ocacheL1_found_at_1 = 0;
2039static UWord stats_ocacheL1_found_at_N = 0;
2040static UWord stats_ocacheL1_misses = 0;
2041static UWord stats_ocacheL1_lossage = 0;
2042static UWord stats_ocacheL1_movefwds = 0;
2043
2044static UWord stats__ocacheL2_refs = 0;
2045static UWord stats__ocacheL2_misses = 0;
2046static UWord stats__ocacheL2_n_nodes_max = 0;
2047
2048/* Cache of 32-bit values, one every 32 bits of address space */
2049
2050#define OC_BITS_PER_LINE 5
2051#define OC_W32S_PER_LINE (1 << (OC_BITS_PER_LINE - 2))
2052
2053static INLINE UWord oc_line_offset ( Addr a ) {
2054 return (a >> 2) & (OC_W32S_PER_LINE - 1);
2055}
2056static INLINE Bool is_valid_oc_tag ( Addr tag ) {
2057 return 0 == (tag & ((1 << OC_BITS_PER_LINE) - 1));
2058}
2059
2060#define OC_LINES_PER_SET 2
2061
2062#define OC_N_SET_BITS 20
2063#define OC_N_SETS (1 << OC_N_SET_BITS)
2064
2065/* These settings give:
2066 64 bit host: ocache: 100,663,296 sizeB 67,108,864 useful
2067 32 bit host: ocache: 92,274,688 sizeB 67,108,864 useful
2068*/
2069
2070#define OC_MOVE_FORWARDS_EVERY_BITS 7
2071
2072
2073typedef
2074 struct {
2075 Addr tag;
2076 UInt w32[OC_W32S_PER_LINE];
2077 UChar descr[OC_W32S_PER_LINE];
2078 }
2079 OCacheLine;
2080
2081/* Classify and also sanity-check 'line'. Return 'e' (empty) if not
2082 in use, 'n' (nonzero) if it contains at least one valid origin tag,
2083 and 'z' if all the represented tags are zero. */
2084static UChar classify_OCacheLine ( OCacheLine* line )
2085{
2086 UWord i;
2087 if (line->tag == 1/*invalid*/)
2088 return 'e'; /* EMPTY */
2089 tl_assert(is_valid_oc_tag(line->tag));
2090 for (i = 0; i < OC_W32S_PER_LINE; i++) {
2091 tl_assert(0 == ((~0xF) & line->descr[i]));
2092 if (line->w32[i] > 0 && line->descr[i] > 0)
2093 return 'n'; /* NONZERO - contains useful info */
2094 }
2095 return 'z'; /* ZERO - no useful info */
2096}
2097
2098typedef
2099 struct {
2100 OCacheLine line[OC_LINES_PER_SET];
2101 }
2102 OCacheSet;
2103
2104typedef
2105 struct {
2106 OCacheSet set[OC_N_SETS];
2107 }
2108 OCache;
2109
sewardj77139802008-05-05 09:48:56 +00002110static OCache* ocacheL1 = NULL;
2111static UWord ocacheL1_event_ctr = 0;
sewardj7cf4e6b2008-05-01 20:24:26 +00002112
2113static void init_ocacheL2 ( void ); /* fwds */
2114static void init_OCache ( void )
2115{
2116 UWord line, set;
sewardj9d624d12008-05-02 13:35:29 +00002117 tl_assert(MC_(clo_mc_level) >= 3);
sewardj77139802008-05-05 09:48:56 +00002118 tl_assert(ocacheL1 == NULL);
2119 ocacheL1 = VG_(am_shadow_alloc)(sizeof(OCache));
2120 if (ocacheL1 == NULL) {
2121 VG_(out_of_memory_NORETURN)( "memcheck:allocating ocacheL1",
sewardj9d624d12008-05-02 13:35:29 +00002122 sizeof(OCache) );
2123 }
sewardj77139802008-05-05 09:48:56 +00002124 tl_assert(ocacheL1 != NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00002125 for (set = 0; set < OC_N_SETS; set++) {
2126 for (line = 0; line < OC_LINES_PER_SET; line++) {
sewardj77139802008-05-05 09:48:56 +00002127 ocacheL1->set[set].line[line].tag = 1/*invalid*/;
sewardj7cf4e6b2008-05-01 20:24:26 +00002128 }
2129 }
2130 init_ocacheL2();
2131}
2132
2133static void moveLineForwards ( OCacheSet* set, UWord lineno )
2134{
2135 OCacheLine tmp;
2136 stats_ocacheL1_movefwds++;
2137 tl_assert(lineno > 0 && lineno < OC_LINES_PER_SET);
2138 tmp = set->line[lineno-1];
2139 set->line[lineno-1] = set->line[lineno];
2140 set->line[lineno] = tmp;
2141}
2142
2143static void zeroise_OCacheLine ( OCacheLine* line, Addr tag ) {
2144 UWord i;
2145 for (i = 0; i < OC_W32S_PER_LINE; i++) {
2146 line->w32[i] = 0; /* NO ORIGIN */
2147 line->descr[i] = 0; /* REALLY REALLY NO ORIGIN! */
2148 }
2149 line->tag = tag;
2150}
2151
2152//////////////////////////////////////////////////////////////
2153//// OCache backing store
2154
2155static OSet* ocacheL2 = NULL;
2156
sewardj9c606bd2008-09-18 18:12:50 +00002157static void* ocacheL2_malloc ( HChar* cc, SizeT szB ) {
2158 return VG_(malloc)(cc, szB);
sewardj7cf4e6b2008-05-01 20:24:26 +00002159}
2160static void ocacheL2_free ( void* v ) {
2161 VG_(free)( v );
2162}
2163
2164/* Stats: # nodes currently in tree */
2165static UWord stats__ocacheL2_n_nodes = 0;
2166
2167static void init_ocacheL2 ( void )
2168{
2169 tl_assert(!ocacheL2);
2170 tl_assert(sizeof(Word) == sizeof(Addr)); /* since OCacheLine.tag :: Addr */
2171 tl_assert(0 == offsetof(OCacheLine,tag));
2172 ocacheL2
2173 = VG_(OSetGen_Create)( offsetof(OCacheLine,tag),
2174 NULL, /* fast cmp */
sewardj9c606bd2008-09-18 18:12:50 +00002175 ocacheL2_malloc, "mc.ioL2", ocacheL2_free );
sewardj7cf4e6b2008-05-01 20:24:26 +00002176 tl_assert(ocacheL2);
2177 stats__ocacheL2_n_nodes = 0;
2178}
2179
2180/* Find line with the given tag in the tree, or NULL if not found. */
2181static OCacheLine* ocacheL2_find_tag ( Addr tag )
2182{
2183 OCacheLine* line;
2184 tl_assert(is_valid_oc_tag(tag));
2185 stats__ocacheL2_refs++;
2186 line = VG_(OSetGen_Lookup)( ocacheL2, &tag );
2187 return line;
2188}
2189
2190/* Delete the line with the given tag from the tree, if it is present, and
2191 free up the associated memory. */
2192static void ocacheL2_del_tag ( Addr tag )
2193{
2194 OCacheLine* line;
2195 tl_assert(is_valid_oc_tag(tag));
2196 stats__ocacheL2_refs++;
2197 line = VG_(OSetGen_Remove)( ocacheL2, &tag );
2198 if (line) {
2199 VG_(OSetGen_FreeNode)(ocacheL2, line);
2200 tl_assert(stats__ocacheL2_n_nodes > 0);
2201 stats__ocacheL2_n_nodes--;
2202 }
2203}
2204
2205/* Add a copy of the given line to the tree. It must not already be
2206 present. */
2207static void ocacheL2_add_line ( OCacheLine* line )
2208{
2209 OCacheLine* copy;
2210 tl_assert(is_valid_oc_tag(line->tag));
2211 copy = VG_(OSetGen_AllocNode)( ocacheL2, sizeof(OCacheLine) );
2212 tl_assert(copy);
2213 *copy = *line;
2214 stats__ocacheL2_refs++;
2215 VG_(OSetGen_Insert)( ocacheL2, copy );
2216 stats__ocacheL2_n_nodes++;
2217 if (stats__ocacheL2_n_nodes > stats__ocacheL2_n_nodes_max)
2218 stats__ocacheL2_n_nodes_max = stats__ocacheL2_n_nodes;
2219}
2220
2221////
2222//////////////////////////////////////////////////////////////
2223
2224__attribute__((noinline))
2225static OCacheLine* find_OCacheLine_SLOW ( Addr a )
2226{
2227 OCacheLine *victim, *inL2;
2228 UChar c;
2229 UWord line;
2230 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2231 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2232 UWord tag = a & tagmask;
2233 tl_assert(setno >= 0 && setno < OC_N_SETS);
2234
2235 /* we already tried line == 0; skip therefore. */
2236 for (line = 1; line < OC_LINES_PER_SET; line++) {
sewardj77139802008-05-05 09:48:56 +00002237 if (ocacheL1->set[setno].line[line].tag == tag) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002238 if (line == 1) {
2239 stats_ocacheL1_found_at_1++;
2240 } else {
2241 stats_ocacheL1_found_at_N++;
2242 }
sewardj77139802008-05-05 09:48:56 +00002243 if (UNLIKELY(0 == (ocacheL1_event_ctr++
sewardj7cf4e6b2008-05-01 20:24:26 +00002244 & ((1<<OC_MOVE_FORWARDS_EVERY_BITS)-1)))) {
sewardj77139802008-05-05 09:48:56 +00002245 moveLineForwards( &ocacheL1->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002246 line--;
2247 }
sewardj77139802008-05-05 09:48:56 +00002248 return &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002249 }
2250 }
2251
2252 /* A miss. Use the last slot. Implicitly this means we're
2253 ejecting the line in the last slot. */
2254 stats_ocacheL1_misses++;
2255 tl_assert(line == OC_LINES_PER_SET);
2256 line--;
2257 tl_assert(line > 0);
2258
2259 /* First, move the to-be-ejected line to the L2 cache. */
sewardj77139802008-05-05 09:48:56 +00002260 victim = &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002261 c = classify_OCacheLine(victim);
2262 switch (c) {
2263 case 'e':
2264 /* the line is empty (has invalid tag); ignore it. */
2265 break;
2266 case 'z':
2267 /* line contains zeroes. We must ensure the backing store is
2268 updated accordingly, either by copying the line there
2269 verbatim, or by ensuring it isn't present there. We
2270 chosse the latter on the basis that it reduces the size of
2271 the backing store. */
2272 ocacheL2_del_tag( victim->tag );
2273 break;
2274 case 'n':
2275 /* line contains at least one real, useful origin. Copy it
2276 to the backing store. */
2277 stats_ocacheL1_lossage++;
2278 inL2 = ocacheL2_find_tag( victim->tag );
2279 if (inL2) {
2280 *inL2 = *victim;
2281 } else {
2282 ocacheL2_add_line( victim );
2283 }
2284 break;
2285 default:
2286 tl_assert(0);
2287 }
2288
2289 /* Now we must reload the L1 cache from the backing tree, if
2290 possible. */
2291 tl_assert(tag != victim->tag); /* stay sane */
2292 inL2 = ocacheL2_find_tag( tag );
2293 if (inL2) {
2294 /* We're in luck. It's in the L2. */
sewardj77139802008-05-05 09:48:56 +00002295 ocacheL1->set[setno].line[line] = *inL2;
sewardj7cf4e6b2008-05-01 20:24:26 +00002296 } else {
2297 /* Missed at both levels of the cache hierarchy. We have to
2298 declare it as full of zeroes (unknown origins). */
2299 stats__ocacheL2_misses++;
sewardj77139802008-05-05 09:48:56 +00002300 zeroise_OCacheLine( &ocacheL1->set[setno].line[line], tag );
sewardj7cf4e6b2008-05-01 20:24:26 +00002301 }
2302
2303 /* Move it one forwards */
sewardj77139802008-05-05 09:48:56 +00002304 moveLineForwards( &ocacheL1->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002305 line--;
2306
sewardj77139802008-05-05 09:48:56 +00002307 return &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002308}
2309
2310static INLINE OCacheLine* find_OCacheLine ( Addr a )
2311{
2312 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2313 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2314 UWord tag = a & tagmask;
2315
2316 stats_ocacheL1_find++;
2317
2318 if (OC_ENABLE_ASSERTIONS) {
2319 tl_assert(setno >= 0 && setno < OC_N_SETS);
2320 tl_assert(0 == (tag & (4 * OC_W32S_PER_LINE - 1)));
2321 }
2322
sewardj77139802008-05-05 09:48:56 +00002323 if (LIKELY(ocacheL1->set[setno].line[0].tag == tag)) {
2324 return &ocacheL1->set[setno].line[0];
sewardj7cf4e6b2008-05-01 20:24:26 +00002325 }
2326
2327 return find_OCacheLine_SLOW( a );
2328}
2329
2330static INLINE void set_aligned_word64_Origin_to_undef ( Addr a, UInt otag )
2331{
2332 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2333 //// Set the origins for a+0 .. a+7
2334 { OCacheLine* line;
2335 UWord lineoff = oc_line_offset(a);
2336 if (OC_ENABLE_ASSERTIONS) {
2337 tl_assert(lineoff >= 0
2338 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2339 }
2340 line = find_OCacheLine( a );
2341 line->descr[lineoff+0] = 0xF;
2342 line->descr[lineoff+1] = 0xF;
2343 line->w32[lineoff+0] = otag;
2344 line->w32[lineoff+1] = otag;
2345 }
2346 //// END inlined, specialised version of MC_(helperc_b_store8)
2347}
2348
2349
2350/*------------------------------------------------------------*/
2351/*--- Aligned fast case permission setters, ---*/
2352/*--- for dealing with stacks ---*/
2353/*------------------------------------------------------------*/
2354
2355/*--------------------- 32-bit ---------------------*/
2356
2357/* Nb: by "aligned" here we mean 4-byte aligned */
2358
2359static INLINE void make_aligned_word32_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002360{
njndbf7ca72006-03-31 11:57:59 +00002361 PROF_EVENT(300, "make_aligned_word32_undefined");
sewardj5d28efc2005-04-21 22:16:29 +00002362
njn1d0825f2006-03-27 11:37:07 +00002363#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002364 make_mem_undefined(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002365#else
njneccf7c02009-01-19 23:42:45 +00002366 {
2367 UWord sm_off;
2368 SecMap* sm;
sewardj5d28efc2005-04-21 22:16:29 +00002369
njneccf7c02009-01-19 23:42:45 +00002370 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2371 PROF_EVENT(301, "make_aligned_word32_undefined-slow1");
2372 make_mem_undefined(a, 4);
2373 return;
2374 }
2375
2376 sm = get_secmap_for_writing_low(a);
2377 sm_off = SM_OFF(a);
2378 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
2379 }
njn1d0825f2006-03-27 11:37:07 +00002380#endif
njn9b007f62003-04-07 14:40:25 +00002381}
2382
sewardj7cf4e6b2008-05-01 20:24:26 +00002383static INLINE
2384void make_aligned_word32_undefined_w_otag ( Addr a, UInt otag )
2385{
2386 make_aligned_word32_undefined(a);
2387 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2388 //// Set the origins for a+0 .. a+3
2389 { OCacheLine* line;
2390 UWord lineoff = oc_line_offset(a);
2391 if (OC_ENABLE_ASSERTIONS) {
2392 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2393 }
2394 line = find_OCacheLine( a );
2395 line->descr[lineoff] = 0xF;
2396 line->w32[lineoff] = otag;
2397 }
2398 //// END inlined, specialised version of MC_(helperc_b_store4)
2399}
sewardj5d28efc2005-04-21 22:16:29 +00002400
njn1d0825f2006-03-27 11:37:07 +00002401static INLINE
2402void make_aligned_word32_noaccess ( Addr a )
sewardj5d28efc2005-04-21 22:16:29 +00002403{
2404 PROF_EVENT(310, "make_aligned_word32_noaccess");
2405
njn1d0825f2006-03-27 11:37:07 +00002406#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002407 MC_(make_mem_noaccess)(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002408#else
njneccf7c02009-01-19 23:42:45 +00002409 {
2410 UWord sm_off;
2411 SecMap* sm;
sewardj5d28efc2005-04-21 22:16:29 +00002412
njneccf7c02009-01-19 23:42:45 +00002413 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2414 PROF_EVENT(311, "make_aligned_word32_noaccess-slow1");
2415 MC_(make_mem_noaccess)(a, 4);
2416 return;
sewardj7cf4e6b2008-05-01 20:24:26 +00002417 }
njneccf7c02009-01-19 23:42:45 +00002418
2419 sm = get_secmap_for_writing_low(a);
2420 sm_off = SM_OFF(a);
2421 sm->vabits8[sm_off] = VA_BITS8_NOACCESS;
2422
2423 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2424 //// Set the origins for a+0 .. a+3.
2425 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2426 OCacheLine* line;
2427 UWord lineoff = oc_line_offset(a);
2428 if (OC_ENABLE_ASSERTIONS) {
2429 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2430 }
2431 line = find_OCacheLine( a );
2432 line->descr[lineoff] = 0;
2433 }
2434 //// END inlined, specialised version of MC_(helperc_b_store4)
sewardj7cf4e6b2008-05-01 20:24:26 +00002435 }
njn1d0825f2006-03-27 11:37:07 +00002436#endif
sewardj5d28efc2005-04-21 22:16:29 +00002437}
2438
sewardj7cf4e6b2008-05-01 20:24:26 +00002439/*--------------------- 64-bit ---------------------*/
sewardj5d28efc2005-04-21 22:16:29 +00002440
njn9b007f62003-04-07 14:40:25 +00002441/* Nb: by "aligned" here we mean 8-byte aligned */
sewardj7cf4e6b2008-05-01 20:24:26 +00002442
2443static INLINE void make_aligned_word64_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002444{
njndbf7ca72006-03-31 11:57:59 +00002445 PROF_EVENT(320, "make_aligned_word64_undefined");
sewardj23eb2fd2005-04-22 16:29:19 +00002446
njn1d0825f2006-03-27 11:37:07 +00002447#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002448 make_mem_undefined(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002449#else
njneccf7c02009-01-19 23:42:45 +00002450 {
2451 UWord sm_off16;
2452 SecMap* sm;
sewardj23eb2fd2005-04-22 16:29:19 +00002453
njneccf7c02009-01-19 23:42:45 +00002454 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2455 PROF_EVENT(321, "make_aligned_word64_undefined-slow1");
2456 make_mem_undefined(a, 8);
2457 return;
2458 }
2459
2460 sm = get_secmap_for_writing_low(a);
2461 sm_off16 = SM_OFF_16(a);
2462 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_UNDEFINED;
2463 }
njn1d0825f2006-03-27 11:37:07 +00002464#endif
njn9b007f62003-04-07 14:40:25 +00002465}
2466
sewardj7cf4e6b2008-05-01 20:24:26 +00002467static INLINE
2468void make_aligned_word64_undefined_w_otag ( Addr a, UInt otag )
2469{
2470 make_aligned_word64_undefined(a);
2471 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2472 //// Set the origins for a+0 .. a+7
2473 { OCacheLine* line;
2474 UWord lineoff = oc_line_offset(a);
2475 tl_assert(lineoff >= 0
2476 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2477 line = find_OCacheLine( a );
2478 line->descr[lineoff+0] = 0xF;
2479 line->descr[lineoff+1] = 0xF;
2480 line->w32[lineoff+0] = otag;
2481 line->w32[lineoff+1] = otag;
2482 }
2483 //// END inlined, specialised version of MC_(helperc_b_store8)
2484}
sewardj23eb2fd2005-04-22 16:29:19 +00002485
njn1d0825f2006-03-27 11:37:07 +00002486static INLINE
2487void make_aligned_word64_noaccess ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002488{
sewardj23eb2fd2005-04-22 16:29:19 +00002489 PROF_EVENT(330, "make_aligned_word64_noaccess");
2490
njn1d0825f2006-03-27 11:37:07 +00002491#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002492 MC_(make_mem_noaccess)(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002493#else
njneccf7c02009-01-19 23:42:45 +00002494 {
2495 UWord sm_off16;
2496 SecMap* sm;
sewardj23eb2fd2005-04-22 16:29:19 +00002497
njneccf7c02009-01-19 23:42:45 +00002498 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2499 PROF_EVENT(331, "make_aligned_word64_noaccess-slow1");
2500 MC_(make_mem_noaccess)(a, 8);
2501 return;
2502 }
sewardj7cf4e6b2008-05-01 20:24:26 +00002503
njneccf7c02009-01-19 23:42:45 +00002504 sm = get_secmap_for_writing_low(a);
2505 sm_off16 = SM_OFF_16(a);
2506 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_NOACCESS;
2507
2508 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2509 //// Clear the origins for a+0 .. a+7.
2510 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2511 OCacheLine* line;
2512 UWord lineoff = oc_line_offset(a);
2513 tl_assert(lineoff >= 0
2514 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2515 line = find_OCacheLine( a );
2516 line->descr[lineoff+0] = 0;
2517 line->descr[lineoff+1] = 0;
2518 }
2519 //// END inlined, specialised version of MC_(helperc_b_store8)
sewardj7cf4e6b2008-05-01 20:24:26 +00002520 }
njn1d0825f2006-03-27 11:37:07 +00002521#endif
njn9b007f62003-04-07 14:40:25 +00002522}
2523
sewardj23eb2fd2005-04-22 16:29:19 +00002524
njn1d0825f2006-03-27 11:37:07 +00002525/*------------------------------------------------------------*/
2526/*--- Stack pointer adjustment ---*/
2527/*------------------------------------------------------------*/
2528
njneccf7c02009-01-19 23:42:45 +00002529#ifdef PERF_FAST_STACK
2530# define MAYBE_USED
2531#else
2532# define MAYBE_USED __attribute__((unused))
2533#endif
2534
sewardj7cf4e6b2008-05-01 20:24:26 +00002535/*--------------- adjustment by 4 bytes ---------------*/
2536
njneccf7c02009-01-19 23:42:45 +00002537MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002538static void VG_REGPARM(2) mc_new_mem_stack_4_w_ECU(Addr new_SP, UInt ecu)
2539{
2540 UInt otag = ecu | MC_OKIND_STACK;
2541 PROF_EVENT(110, "new_mem_stack_4");
2542 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2543 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2544 } else {
2545 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 4, otag );
2546 }
2547}
2548
njneccf7c02009-01-19 23:42:45 +00002549MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002550static void VG_REGPARM(1) mc_new_mem_stack_4(Addr new_SP)
2551{
2552 PROF_EVENT(110, "new_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002553 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002554 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njn1d0825f2006-03-27 11:37:07 +00002555 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002556 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 4 );
njn1d0825f2006-03-27 11:37:07 +00002557 }
2558}
2559
njneccf7c02009-01-19 23:42:45 +00002560MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002561static void VG_REGPARM(1) mc_die_mem_stack_4(Addr new_SP)
2562{
2563 PROF_EVENT(120, "die_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002564 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002565 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002566 } else {
njndbf7ca72006-03-31 11:57:59 +00002567 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-4, 4 );
njn1d0825f2006-03-27 11:37:07 +00002568 }
2569}
2570
sewardj7cf4e6b2008-05-01 20:24:26 +00002571/*--------------- adjustment by 8 bytes ---------------*/
2572
njneccf7c02009-01-19 23:42:45 +00002573MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002574static void VG_REGPARM(2) mc_new_mem_stack_8_w_ECU(Addr new_SP, UInt ecu)
2575{
2576 UInt otag = ecu | MC_OKIND_STACK;
2577 PROF_EVENT(111, "new_mem_stack_8");
2578 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2579 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2580 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2581 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2582 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2583 } else {
2584 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 8, otag );
2585 }
2586}
2587
njneccf7c02009-01-19 23:42:45 +00002588MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002589static void VG_REGPARM(1) mc_new_mem_stack_8(Addr new_SP)
2590{
2591 PROF_EVENT(111, "new_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002592 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002593 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
sewardj05a46732006-10-17 01:28:10 +00002594 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002595 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002596 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002597 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002598 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 8 );
njn1d0825f2006-03-27 11:37:07 +00002599 }
2600}
2601
njneccf7c02009-01-19 23:42:45 +00002602MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002603static void VG_REGPARM(1) mc_die_mem_stack_8(Addr new_SP)
2604{
2605 PROF_EVENT(121, "die_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002606 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002607 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002608 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002609 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
2610 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002611 } else {
njndbf7ca72006-03-31 11:57:59 +00002612 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-8, 8 );
njn1d0825f2006-03-27 11:37:07 +00002613 }
2614}
2615
sewardj7cf4e6b2008-05-01 20:24:26 +00002616/*--------------- adjustment by 12 bytes ---------------*/
2617
njneccf7c02009-01-19 23:42:45 +00002618MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002619static void VG_REGPARM(2) mc_new_mem_stack_12_w_ECU(Addr new_SP, UInt ecu)
2620{
2621 UInt otag = ecu | MC_OKIND_STACK;
2622 PROF_EVENT(112, "new_mem_stack_12");
2623 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2624 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2625 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2626 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2627 /* from previous test we don't have 8-alignment at offset +0,
2628 hence must have 8 alignment at offsets +4/-4. Hence safe to
2629 do 4 at +0 and then 8 at +4/. */
2630 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2631 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2632 } else {
2633 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 12, otag );
2634 }
2635}
2636
njneccf7c02009-01-19 23:42:45 +00002637MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002638static void VG_REGPARM(1) mc_new_mem_stack_12(Addr new_SP)
2639{
2640 PROF_EVENT(112, "new_mem_stack_12");
sewardj05a46732006-10-17 01:28:10 +00002641 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002642 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002643 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002644 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002645 /* from previous test we don't have 8-alignment at offset +0,
2646 hence must have 8 alignment at offsets +4/-4. Hence safe to
2647 do 4 at +0 and then 8 at +4/. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002648 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002649 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002650 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002651 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 12 );
njn1d0825f2006-03-27 11:37:07 +00002652 }
2653}
2654
njneccf7c02009-01-19 23:42:45 +00002655MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002656static void VG_REGPARM(1) mc_die_mem_stack_12(Addr new_SP)
2657{
2658 PROF_EVENT(122, "die_mem_stack_12");
2659 /* Note the -12 in the test */
sewardj43fcfd92006-10-17 23:14:42 +00002660 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP-12 )) {
2661 /* We have 8-alignment at -12, hence ok to do 8 at -12 and 4 at
2662 -4. */
njndbf7ca72006-03-31 11:57:59 +00002663 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2664 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
sewardj05a46732006-10-17 01:28:10 +00002665 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002666 /* We have 4-alignment at +0, but we don't have 8-alignment at
2667 -12. So we must have 8-alignment at -8. Hence do 4 at -12
2668 and then 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002669 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2670 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
njn1d0825f2006-03-27 11:37:07 +00002671 } else {
njndbf7ca72006-03-31 11:57:59 +00002672 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-12, 12 );
njn1d0825f2006-03-27 11:37:07 +00002673 }
2674}
2675
sewardj7cf4e6b2008-05-01 20:24:26 +00002676/*--------------- adjustment by 16 bytes ---------------*/
2677
njneccf7c02009-01-19 23:42:45 +00002678MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002679static void VG_REGPARM(2) mc_new_mem_stack_16_w_ECU(Addr new_SP, UInt ecu)
2680{
2681 UInt otag = ecu | MC_OKIND_STACK;
2682 PROF_EVENT(113, "new_mem_stack_16");
2683 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2684 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
2685 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2686 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2687 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2688 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2689 Hence do 4 at +0, 8 at +4, 4 at +12. */
2690 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2691 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2692 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2693 } else {
2694 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 16, otag );
2695 }
2696}
2697
njneccf7c02009-01-19 23:42:45 +00002698MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002699static void VG_REGPARM(1) mc_new_mem_stack_16(Addr new_SP)
2700{
2701 PROF_EVENT(113, "new_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002702 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002703 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002704 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002705 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002706 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002707 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2708 Hence do 4 at +0, 8 at +4, 4 at +12. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002709 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002710 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
2711 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
njn1d0825f2006-03-27 11:37:07 +00002712 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002713 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 16 );
njn1d0825f2006-03-27 11:37:07 +00002714 }
2715}
2716
njneccf7c02009-01-19 23:42:45 +00002717MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002718static void VG_REGPARM(1) mc_die_mem_stack_16(Addr new_SP)
2719{
2720 PROF_EVENT(123, "die_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002721 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002722 /* Have 8-alignment at +0, hence do 8 at -16 and 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002723 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2724 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002725 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002726 /* 8 alignment must be at -12. Do 4 at -16, 8 at -12, 4 at -4. */
njndbf7ca72006-03-31 11:57:59 +00002727 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2728 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2729 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002730 } else {
njndbf7ca72006-03-31 11:57:59 +00002731 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-16, 16 );
njn1d0825f2006-03-27 11:37:07 +00002732 }
2733}
2734
sewardj7cf4e6b2008-05-01 20:24:26 +00002735/*--------------- adjustment by 32 bytes ---------------*/
2736
njneccf7c02009-01-19 23:42:45 +00002737MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002738static void VG_REGPARM(2) mc_new_mem_stack_32_w_ECU(Addr new_SP, UInt ecu)
2739{
2740 UInt otag = ecu | MC_OKIND_STACK;
2741 PROF_EVENT(114, "new_mem_stack_32");
2742 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2743 /* Straightforward */
2744 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2745 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2746 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2747 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2748 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2749 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2750 +0,+28. */
2751 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2752 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2753 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2754 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+20, otag );
2755 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+28, otag );
2756 } else {
2757 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 32, otag );
2758 }
2759}
2760
njneccf7c02009-01-19 23:42:45 +00002761MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002762static void VG_REGPARM(1) mc_new_mem_stack_32(Addr new_SP)
2763{
2764 PROF_EVENT(114, "new_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002765 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002766 /* Straightforward */
sewardj7cf4e6b2008-05-01 20:24:26 +00002767 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2768 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002769 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2770 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
sewardj05a46732006-10-17 01:28:10 +00002771 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002772 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2773 +0,+28. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002774 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2775 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njndbf7ca72006-03-31 11:57:59 +00002776 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
2777 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+20 );
2778 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+28 );
njn1d0825f2006-03-27 11:37:07 +00002779 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002780 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 32 );
njn1d0825f2006-03-27 11:37:07 +00002781 }
2782}
2783
njneccf7c02009-01-19 23:42:45 +00002784MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002785static void VG_REGPARM(1) mc_die_mem_stack_32(Addr new_SP)
2786{
2787 PROF_EVENT(124, "die_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002788 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002789 /* Straightforward */
njndbf7ca72006-03-31 11:57:59 +00002790 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2791 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2792 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2793 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
sewardj05a46732006-10-17 01:28:10 +00002794 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002795 /* 8 alignment must be at -4 etc. Hence do 8 at -12,-20,-28 and
2796 4 at -32,-4. */
njndbf7ca72006-03-31 11:57:59 +00002797 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2798 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-28 );
2799 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-20 );
2800 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2801 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002802 } else {
njndbf7ca72006-03-31 11:57:59 +00002803 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-32, 32 );
njn1d0825f2006-03-27 11:37:07 +00002804 }
2805}
2806
sewardj7cf4e6b2008-05-01 20:24:26 +00002807/*--------------- adjustment by 112 bytes ---------------*/
2808
njneccf7c02009-01-19 23:42:45 +00002809MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002810static void VG_REGPARM(2) mc_new_mem_stack_112_w_ECU(Addr new_SP, UInt ecu)
2811{
2812 UInt otag = ecu | MC_OKIND_STACK;
2813 PROF_EVENT(115, "new_mem_stack_112");
2814 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2815 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2816 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2817 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2818 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2819 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2820 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2821 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2822 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2823 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2824 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2825 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2826 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2827 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2828 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2829 } else {
2830 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 112, otag );
2831 }
2832}
2833
njneccf7c02009-01-19 23:42:45 +00002834MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002835static void VG_REGPARM(1) mc_new_mem_stack_112(Addr new_SP)
2836{
2837 PROF_EVENT(115, "new_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002838 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002839 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2840 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002841 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2842 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2843 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2844 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2845 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2846 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2847 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2848 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2849 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2850 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2851 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002852 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
njn1d0825f2006-03-27 11:37:07 +00002853 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002854 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 112 );
njn1d0825f2006-03-27 11:37:07 +00002855 }
2856}
2857
njneccf7c02009-01-19 23:42:45 +00002858MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002859static void VG_REGPARM(1) mc_die_mem_stack_112(Addr new_SP)
2860{
2861 PROF_EVENT(125, "die_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002862 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002863 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2864 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2865 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2866 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2867 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2868 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2869 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2870 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2871 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2872 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2873 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2874 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2875 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2876 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002877 } else {
njndbf7ca72006-03-31 11:57:59 +00002878 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-112, 112 );
njn1d0825f2006-03-27 11:37:07 +00002879 }
2880}
2881
sewardj7cf4e6b2008-05-01 20:24:26 +00002882/*--------------- adjustment by 128 bytes ---------------*/
2883
njneccf7c02009-01-19 23:42:45 +00002884MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002885static void VG_REGPARM(2) mc_new_mem_stack_128_w_ECU(Addr new_SP, UInt ecu)
2886{
2887 UInt otag = ecu | MC_OKIND_STACK;
2888 PROF_EVENT(116, "new_mem_stack_128");
2889 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2890 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2891 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2892 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2893 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2894 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2895 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2896 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2897 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2898 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2899 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2900 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2901 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2902 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2903 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2904 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2905 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2906 } else {
2907 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 128, otag );
2908 }
2909}
2910
njneccf7c02009-01-19 23:42:45 +00002911MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002912static void VG_REGPARM(1) mc_new_mem_stack_128(Addr new_SP)
2913{
2914 PROF_EVENT(116, "new_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002915 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002916 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2917 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002918 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2919 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2920 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2921 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2922 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2923 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2924 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2925 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2926 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2927 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2928 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002929 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2930 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2931 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
njn1d0825f2006-03-27 11:37:07 +00002932 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002933 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 128 );
njn1d0825f2006-03-27 11:37:07 +00002934 }
2935}
2936
njneccf7c02009-01-19 23:42:45 +00002937MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002938static void VG_REGPARM(1) mc_die_mem_stack_128(Addr new_SP)
2939{
2940 PROF_EVENT(126, "die_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002941 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002942 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2943 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2944 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2945 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2946 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2947 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2948 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2949 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2950 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2951 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2952 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2953 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2954 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2955 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2956 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2957 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002958 } else {
njndbf7ca72006-03-31 11:57:59 +00002959 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-128, 128 );
njn1d0825f2006-03-27 11:37:07 +00002960 }
2961}
2962
sewardj7cf4e6b2008-05-01 20:24:26 +00002963/*--------------- adjustment by 144 bytes ---------------*/
2964
njneccf7c02009-01-19 23:42:45 +00002965MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002966static void VG_REGPARM(2) mc_new_mem_stack_144_w_ECU(Addr new_SP, UInt ecu)
2967{
2968 UInt otag = ecu | MC_OKIND_STACK;
2969 PROF_EVENT(117, "new_mem_stack_144");
2970 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2971 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2972 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2973 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2974 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2975 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2976 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2977 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2978 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2979 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2980 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2981 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2982 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2983 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2984 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2985 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2986 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2987 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
2988 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
2989 } else {
2990 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 144, otag );
2991 }
2992}
2993
njneccf7c02009-01-19 23:42:45 +00002994MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002995static void VG_REGPARM(1) mc_new_mem_stack_144(Addr new_SP)
2996{
2997 PROF_EVENT(117, "new_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00002998 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002999 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
3000 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00003001 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
3002 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
3003 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
3004 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
3005 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
3006 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
3007 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
3008 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
3009 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
3010 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
3011 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00003012 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
3013 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
3014 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
3015 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
3016 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
njn1d0825f2006-03-27 11:37:07 +00003017 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003018 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 144 );
njn1d0825f2006-03-27 11:37:07 +00003019 }
3020}
3021
njneccf7c02009-01-19 23:42:45 +00003022MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003023static void VG_REGPARM(1) mc_die_mem_stack_144(Addr new_SP)
3024{
3025 PROF_EVENT(127, "die_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00003026 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00003027 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
3028 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
3029 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
3030 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
3031 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
3032 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
3033 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
3034 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
3035 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
3036 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
3037 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
3038 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
3039 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3040 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3041 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3042 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3043 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3044 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003045 } else {
njndbf7ca72006-03-31 11:57:59 +00003046 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-144, 144 );
njn1d0825f2006-03-27 11:37:07 +00003047 }
3048}
3049
sewardj7cf4e6b2008-05-01 20:24:26 +00003050/*--------------- adjustment by 160 bytes ---------------*/
3051
njneccf7c02009-01-19 23:42:45 +00003052MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00003053static void VG_REGPARM(2) mc_new_mem_stack_160_w_ECU(Addr new_SP, UInt ecu)
3054{
3055 UInt otag = ecu | MC_OKIND_STACK;
3056 PROF_EVENT(118, "new_mem_stack_160");
3057 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
3058 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
3059 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
3060 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
3061 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
3062 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
3063 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
3064 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
3065 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
3066 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
3067 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
3068 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
3069 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
3070 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
3071 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
3072 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
3073 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
3074 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
3075 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
3076 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+144, otag );
3077 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+152, otag );
3078 } else {
3079 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 160, otag );
3080 }
3081}
3082
njneccf7c02009-01-19 23:42:45 +00003083MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003084static void VG_REGPARM(1) mc_new_mem_stack_160(Addr new_SP)
3085{
3086 PROF_EVENT(118, "new_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003087 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003088 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
3089 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00003090 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
3091 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
3092 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
3093 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
3094 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
3095 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
3096 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
3097 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
3098 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
3099 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
3100 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00003101 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
3102 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
3103 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
3104 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
3105 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
3106 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+144 );
3107 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+152 );
njn1d0825f2006-03-27 11:37:07 +00003108 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003109 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 160 );
njn1d0825f2006-03-27 11:37:07 +00003110 }
3111}
3112
njneccf7c02009-01-19 23:42:45 +00003113MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003114static void VG_REGPARM(1) mc_die_mem_stack_160(Addr new_SP)
3115{
3116 PROF_EVENT(128, "die_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003117 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00003118 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-160);
3119 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-152);
3120 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
3121 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
3122 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
3123 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
3124 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
3125 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
3126 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
3127 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
3128 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
3129 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
3130 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
3131 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
3132 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3133 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3134 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3135 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3136 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3137 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003138 } else {
njndbf7ca72006-03-31 11:57:59 +00003139 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-160, 160 );
njn1d0825f2006-03-27 11:37:07 +00003140 }
3141}
3142
sewardj7cf4e6b2008-05-01 20:24:26 +00003143/*--------------- adjustment by N bytes ---------------*/
3144
3145static void mc_new_mem_stack_w_ECU ( Addr a, SizeT len, UInt ecu )
3146{
3147 UInt otag = ecu | MC_OKIND_STACK;
3148 PROF_EVENT(115, "new_mem_stack_w_otag");
3149 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + a, len, otag );
3150}
3151
njn1d0825f2006-03-27 11:37:07 +00003152static void mc_new_mem_stack ( Addr a, SizeT len )
3153{
3154 PROF_EVENT(115, "new_mem_stack");
sewardj7cf4e6b2008-05-01 20:24:26 +00003155 make_mem_undefined ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003156}
3157
3158static void mc_die_mem_stack ( Addr a, SizeT len )
3159{
3160 PROF_EVENT(125, "die_mem_stack");
njndbf7ca72006-03-31 11:57:59 +00003161 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003162}
njn9b007f62003-04-07 14:40:25 +00003163
sewardj45d94cc2005-04-20 14:44:11 +00003164
njn1d0825f2006-03-27 11:37:07 +00003165/* The AMD64 ABI says:
3166
3167 "The 128-byte area beyond the location pointed to by %rsp is considered
3168 to be reserved and shall not be modified by signal or interrupt
3169 handlers. Therefore, functions may use this area for temporary data
3170 that is not needed across function calls. In particular, leaf functions
3171 may use this area for their entire stack frame, rather than adjusting
3172 the stack pointer in the prologue and epilogue. This area is known as
3173 red zone [sic]."
3174
3175 So after any call or return we need to mark this redzone as containing
3176 undefined values.
3177
3178 Consider this: we're in function f. f calls g. g moves rsp down
3179 modestly (say 16 bytes) and writes stuff all over the red zone, making it
3180 defined. g returns. f is buggy and reads from parts of the red zone
3181 that it didn't write on. But because g filled that area in, f is going
3182 to be picking up defined V bits and so any errors from reading bits of
3183 the red zone it didn't write, will be missed. The only solution I could
3184 think of was to make the red zone undefined when g returns to f.
3185
3186 This is in accordance with the ABI, which makes it clear the redzone
3187 is volatile across function calls.
3188
3189 The problem occurs the other way round too: f could fill the RZ up
3190 with defined values and g could mistakenly read them. So the RZ
3191 also needs to be nuked on function calls.
3192*/
sewardj7cf4e6b2008-05-01 20:24:26 +00003193
3194
3195/* Here's a simple cache to hold nia -> ECU mappings. It could be
3196 improved so as to have a lower miss rate. */
3197
3198static UWord stats__nia_cache_queries = 0;
3199static UWord stats__nia_cache_misses = 0;
3200
3201typedef
3202 struct { UWord nia0; UWord ecu0; /* nia0 maps to ecu0 */
3203 UWord nia1; UWord ecu1; } /* nia1 maps to ecu1 */
3204 WCacheEnt;
3205
3206#define N_NIA_TO_ECU_CACHE 511
3207
3208static WCacheEnt nia_to_ecu_cache[N_NIA_TO_ECU_CACHE];
3209
3210static void init_nia_to_ecu_cache ( void )
sewardj826ec492005-05-12 18:05:00 +00003211{
sewardj7cf4e6b2008-05-01 20:24:26 +00003212 UWord i;
3213 Addr zero_addr = 0;
3214 ExeContext* zero_ec;
3215 UInt zero_ecu;
3216 /* Fill all the slots with an entry for address zero, and the
3217 relevant otags accordingly. Hence the cache is initially filled
3218 with valid data. */
3219 zero_ec = VG_(make_depth_1_ExeContext_from_Addr)(zero_addr);
3220 tl_assert(zero_ec);
3221 zero_ecu = VG_(get_ECU_from_ExeContext)(zero_ec);
3222 tl_assert(VG_(is_plausible_ECU)(zero_ecu));
3223 for (i = 0; i < N_NIA_TO_ECU_CACHE; i++) {
3224 nia_to_ecu_cache[i].nia0 = zero_addr;
3225 nia_to_ecu_cache[i].ecu0 = zero_ecu;
3226 nia_to_ecu_cache[i].nia1 = zero_addr;
3227 nia_to_ecu_cache[i].ecu1 = zero_ecu;
3228 }
3229}
3230
3231static inline UInt convert_nia_to_ecu ( Addr nia )
3232{
3233 UWord i;
3234 UInt ecu;
3235 ExeContext* ec;
3236
3237 tl_assert( sizeof(nia_to_ecu_cache[0].nia1) == sizeof(nia) );
3238
3239 stats__nia_cache_queries++;
3240 i = nia % N_NIA_TO_ECU_CACHE;
3241 tl_assert(i >= 0 && i < N_NIA_TO_ECU_CACHE);
3242
3243 if (LIKELY( nia_to_ecu_cache[i].nia0 == nia ))
3244 return nia_to_ecu_cache[i].ecu0;
3245
3246 if (LIKELY( nia_to_ecu_cache[i].nia1 == nia )) {
3247# define SWAP(_w1,_w2) { UWord _t = _w1; _w1 = _w2; _w2 = _t; }
3248 SWAP( nia_to_ecu_cache[i].nia0, nia_to_ecu_cache[i].nia1 );
3249 SWAP( nia_to_ecu_cache[i].ecu0, nia_to_ecu_cache[i].ecu1 );
3250# undef SWAP
3251 return nia_to_ecu_cache[i].ecu0;
3252 }
3253
3254 stats__nia_cache_misses++;
3255 ec = VG_(make_depth_1_ExeContext_from_Addr)(nia);
3256 tl_assert(ec);
3257 ecu = VG_(get_ECU_from_ExeContext)(ec);
3258 tl_assert(VG_(is_plausible_ECU)(ecu));
3259
3260 nia_to_ecu_cache[i].nia1 = nia_to_ecu_cache[i].nia0;
3261 nia_to_ecu_cache[i].ecu1 = nia_to_ecu_cache[i].ecu0;
3262
3263 nia_to_ecu_cache[i].nia0 = nia;
3264 nia_to_ecu_cache[i].ecu0 = (UWord)ecu;
3265 return ecu;
3266}
3267
3268
3269/* Note that this serves both the origin-tracking and
3270 no-origin-tracking modes. We assume that calls to it are
3271 sufficiently infrequent that it isn't worth specialising for the
3272 with/without origin-tracking cases. */
3273void MC_(helperc_MAKE_STACK_UNINIT) ( Addr base, UWord len, Addr nia )
3274{
3275 UInt otag;
sewardj826ec492005-05-12 18:05:00 +00003276 tl_assert(sizeof(UWord) == sizeof(SizeT));
sewardj2a3a1a72005-05-12 23:25:43 +00003277 if (0)
barta0b6b2c2008-07-07 06:49:24 +00003278 VG_(printf)("helperc_MAKE_STACK_UNINIT (%#lx,%lu,nia=%#lx)\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00003279 base, len, nia );
3280
3281 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3282 UInt ecu = convert_nia_to_ecu ( nia );
3283 tl_assert(VG_(is_plausible_ECU)(ecu));
3284 otag = ecu | MC_OKIND_STACK;
3285 } else {
3286 tl_assert(nia == 0);
3287 otag = 0;
3288 }
sewardj2a3a1a72005-05-12 23:25:43 +00003289
3290# if 0
3291 /* Really slow version */
sewardj7cf4e6b2008-05-01 20:24:26 +00003292 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003293# endif
3294
3295# if 0
3296 /* Slow(ish) version, which is fairly easily seen to be correct.
3297 */
bart5dd8e6a2008-03-22 08:04:29 +00003298 if (LIKELY( VG_IS_8_ALIGNED(base) && len==128 )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003299 make_aligned_word64_undefined(base + 0, otag);
3300 make_aligned_word64_undefined(base + 8, otag);
3301 make_aligned_word64_undefined(base + 16, otag);
3302 make_aligned_word64_undefined(base + 24, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003303
sewardj7cf4e6b2008-05-01 20:24:26 +00003304 make_aligned_word64_undefined(base + 32, otag);
3305 make_aligned_word64_undefined(base + 40, otag);
3306 make_aligned_word64_undefined(base + 48, otag);
3307 make_aligned_word64_undefined(base + 56, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003308
sewardj7cf4e6b2008-05-01 20:24:26 +00003309 make_aligned_word64_undefined(base + 64, otag);
3310 make_aligned_word64_undefined(base + 72, otag);
3311 make_aligned_word64_undefined(base + 80, otag);
3312 make_aligned_word64_undefined(base + 88, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003313
sewardj7cf4e6b2008-05-01 20:24:26 +00003314 make_aligned_word64_undefined(base + 96, otag);
3315 make_aligned_word64_undefined(base + 104, otag);
3316 make_aligned_word64_undefined(base + 112, otag);
3317 make_aligned_word64_undefined(base + 120, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003318 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003319 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003320 }
3321# endif
3322
3323 /* Idea is: go fast when
3324 * 8-aligned and length is 128
3325 * the sm is available in the main primary map
njn1d0825f2006-03-27 11:37:07 +00003326 * the address range falls entirely with a single secondary map
3327 If all those conditions hold, just update the V+A bits by writing
3328 directly into the vabits array. (If the sm was distinguished, this
3329 will make a copy and then write to it.)
sewardj2a3a1a72005-05-12 23:25:43 +00003330 */
sewardj7cf4e6b2008-05-01 20:24:26 +00003331
bart5dd8e6a2008-03-22 08:04:29 +00003332 if (LIKELY( len == 128 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003333 /* Now we know the address range is suitably sized and aligned. */
3334 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003335 UWord a_hi = (UWord)(base + 128 - 1);
njn1d0825f2006-03-27 11:37:07 +00003336 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003337 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003338 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003339 SecMap* sm = get_secmap_for_writing_low(a_lo);
3340 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2a3a1a72005-05-12 23:25:43 +00003341 /* Now we know that the entire address range falls within a
3342 single secondary map, and that that secondary 'lives' in
3343 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003344 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003345 // Finally, we know that the range is entirely within one secmap.
3346 UWord v_off = SM_OFF(a_lo);
3347 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003348 p[ 0] = VA_BITS16_UNDEFINED;
3349 p[ 1] = VA_BITS16_UNDEFINED;
3350 p[ 2] = VA_BITS16_UNDEFINED;
3351 p[ 3] = VA_BITS16_UNDEFINED;
3352 p[ 4] = VA_BITS16_UNDEFINED;
3353 p[ 5] = VA_BITS16_UNDEFINED;
3354 p[ 6] = VA_BITS16_UNDEFINED;
3355 p[ 7] = VA_BITS16_UNDEFINED;
3356 p[ 8] = VA_BITS16_UNDEFINED;
3357 p[ 9] = VA_BITS16_UNDEFINED;
3358 p[10] = VA_BITS16_UNDEFINED;
3359 p[11] = VA_BITS16_UNDEFINED;
3360 p[12] = VA_BITS16_UNDEFINED;
3361 p[13] = VA_BITS16_UNDEFINED;
3362 p[14] = VA_BITS16_UNDEFINED;
3363 p[15] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003364 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3365 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3366 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3367 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3368 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3369 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3370 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3371 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3372 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3373 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3374 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3375 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3376 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3377 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3378 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3379 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3380 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3381 }
sewardj2a3a1a72005-05-12 23:25:43 +00003382 return;
njn1d0825f2006-03-27 11:37:07 +00003383 }
sewardj2a3a1a72005-05-12 23:25:43 +00003384 }
3385 }
3386
sewardj2e1a6772006-01-18 04:16:27 +00003387 /* 288 bytes (36 ULongs) is the magic value for ELF ppc64. */
bart5dd8e6a2008-03-22 08:04:29 +00003388 if (LIKELY( len == 288 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003389 /* Now we know the address range is suitably sized and aligned. */
3390 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003391 UWord a_hi = (UWord)(base + 288 - 1);
njn1d0825f2006-03-27 11:37:07 +00003392 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003393 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003394 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003395 SecMap* sm = get_secmap_for_writing_low(a_lo);
3396 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2e1a6772006-01-18 04:16:27 +00003397 /* Now we know that the entire address range falls within a
3398 single secondary map, and that that secondary 'lives' in
3399 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003400 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003401 // Finally, we know that the range is entirely within one secmap.
3402 UWord v_off = SM_OFF(a_lo);
3403 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003404 p[ 0] = VA_BITS16_UNDEFINED;
3405 p[ 1] = VA_BITS16_UNDEFINED;
3406 p[ 2] = VA_BITS16_UNDEFINED;
3407 p[ 3] = VA_BITS16_UNDEFINED;
3408 p[ 4] = VA_BITS16_UNDEFINED;
3409 p[ 5] = VA_BITS16_UNDEFINED;
3410 p[ 6] = VA_BITS16_UNDEFINED;
3411 p[ 7] = VA_BITS16_UNDEFINED;
3412 p[ 8] = VA_BITS16_UNDEFINED;
3413 p[ 9] = VA_BITS16_UNDEFINED;
3414 p[10] = VA_BITS16_UNDEFINED;
3415 p[11] = VA_BITS16_UNDEFINED;
3416 p[12] = VA_BITS16_UNDEFINED;
3417 p[13] = VA_BITS16_UNDEFINED;
3418 p[14] = VA_BITS16_UNDEFINED;
3419 p[15] = VA_BITS16_UNDEFINED;
3420 p[16] = VA_BITS16_UNDEFINED;
3421 p[17] = VA_BITS16_UNDEFINED;
3422 p[18] = VA_BITS16_UNDEFINED;
3423 p[19] = VA_BITS16_UNDEFINED;
3424 p[20] = VA_BITS16_UNDEFINED;
3425 p[21] = VA_BITS16_UNDEFINED;
3426 p[22] = VA_BITS16_UNDEFINED;
3427 p[23] = VA_BITS16_UNDEFINED;
3428 p[24] = VA_BITS16_UNDEFINED;
3429 p[25] = VA_BITS16_UNDEFINED;
3430 p[26] = VA_BITS16_UNDEFINED;
3431 p[27] = VA_BITS16_UNDEFINED;
3432 p[28] = VA_BITS16_UNDEFINED;
3433 p[29] = VA_BITS16_UNDEFINED;
3434 p[30] = VA_BITS16_UNDEFINED;
3435 p[31] = VA_BITS16_UNDEFINED;
3436 p[32] = VA_BITS16_UNDEFINED;
3437 p[33] = VA_BITS16_UNDEFINED;
3438 p[34] = VA_BITS16_UNDEFINED;
3439 p[35] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003440 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3441 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3442 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3443 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3444 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3445 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3446 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3447 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3448 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3449 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3450 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3451 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3452 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3453 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3454 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3455 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3456 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3457 set_aligned_word64_Origin_to_undef( base + 8 * 16, otag );
3458 set_aligned_word64_Origin_to_undef( base + 8 * 17, otag );
3459 set_aligned_word64_Origin_to_undef( base + 8 * 18, otag );
3460 set_aligned_word64_Origin_to_undef( base + 8 * 19, otag );
3461 set_aligned_word64_Origin_to_undef( base + 8 * 20, otag );
3462 set_aligned_word64_Origin_to_undef( base + 8 * 21, otag );
3463 set_aligned_word64_Origin_to_undef( base + 8 * 22, otag );
3464 set_aligned_word64_Origin_to_undef( base + 8 * 23, otag );
3465 set_aligned_word64_Origin_to_undef( base + 8 * 24, otag );
3466 set_aligned_word64_Origin_to_undef( base + 8 * 25, otag );
3467 set_aligned_word64_Origin_to_undef( base + 8 * 26, otag );
3468 set_aligned_word64_Origin_to_undef( base + 8 * 27, otag );
3469 set_aligned_word64_Origin_to_undef( base + 8 * 28, otag );
3470 set_aligned_word64_Origin_to_undef( base + 8 * 29, otag );
3471 set_aligned_word64_Origin_to_undef( base + 8 * 30, otag );
3472 set_aligned_word64_Origin_to_undef( base + 8 * 31, otag );
3473 set_aligned_word64_Origin_to_undef( base + 8 * 32, otag );
3474 set_aligned_word64_Origin_to_undef( base + 8 * 33, otag );
3475 set_aligned_word64_Origin_to_undef( base + 8 * 34, otag );
3476 set_aligned_word64_Origin_to_undef( base + 8 * 35, otag );
3477 }
sewardj2e1a6772006-01-18 04:16:27 +00003478 return;
njn1d0825f2006-03-27 11:37:07 +00003479 }
sewardj2e1a6772006-01-18 04:16:27 +00003480 }
3481 }
3482
sewardj2a3a1a72005-05-12 23:25:43 +00003483 /* else fall into slow case */
sewardj7cf4e6b2008-05-01 20:24:26 +00003484 MC_(make_mem_undefined_w_otag)(base, len, otag);
sewardj826ec492005-05-12 18:05:00 +00003485}
3486
3487
nethercote8b76fe52004-11-08 19:20:09 +00003488/*------------------------------------------------------------*/
3489/*--- Checking memory ---*/
3490/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003491
sewardje4ccc012005-05-02 12:53:38 +00003492typedef
3493 enum {
3494 MC_Ok = 5,
3495 MC_AddrErr = 6,
3496 MC_ValueErr = 7
3497 }
3498 MC_ReadResult;
3499
3500
njn25e49d8e72002-09-23 09:36:25 +00003501/* Check permissions for address range. If inadequate permissions
3502 exist, *bad_addr is set to the offending address, so the caller can
3503 know what it is. */
3504
sewardjecf8e102003-07-12 12:11:39 +00003505/* Returns True if [a .. a+len) is not addressible. Otherwise,
3506 returns False, and if bad_addr is non-NULL, sets *bad_addr to
3507 indicate the lowest failing address. Functions below are
3508 similar. */
njndbf7ca72006-03-31 11:57:59 +00003509Bool MC_(check_mem_is_noaccess) ( Addr a, SizeT len, Addr* bad_addr )
sewardjecf8e102003-07-12 12:11:39 +00003510{
nethercote451eae92004-11-02 13:06:32 +00003511 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003512 UWord vabits2;
3513
njndbf7ca72006-03-31 11:57:59 +00003514 PROF_EVENT(60, "check_mem_is_noaccess");
sewardjecf8e102003-07-12 12:11:39 +00003515 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003516 PROF_EVENT(61, "check_mem_is_noaccess(loop)");
njn1d0825f2006-03-27 11:37:07 +00003517 vabits2 = get_vabits2(a);
3518 if (VA_BITS2_NOACCESS != vabits2) {
3519 if (bad_addr != NULL) *bad_addr = a;
sewardjecf8e102003-07-12 12:11:39 +00003520 return False;
3521 }
3522 a++;
3523 }
3524 return True;
3525}
3526
sewardj7cf4e6b2008-05-01 20:24:26 +00003527static Bool is_mem_addressable ( Addr a, SizeT len,
3528 /*OUT*/Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +00003529{
nethercote451eae92004-11-02 13:06:32 +00003530 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003531 UWord vabits2;
3532
njndbf7ca72006-03-31 11:57:59 +00003533 PROF_EVENT(62, "is_mem_addressable");
njn25e49d8e72002-09-23 09:36:25 +00003534 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003535 PROF_EVENT(63, "is_mem_addressable(loop)");
njn1d0825f2006-03-27 11:37:07 +00003536 vabits2 = get_vabits2(a);
3537 if (VA_BITS2_NOACCESS == vabits2) {
njn25e49d8e72002-09-23 09:36:25 +00003538 if (bad_addr != NULL) *bad_addr = a;
3539 return False;
3540 }
3541 a++;
3542 }
3543 return True;
3544}
3545
sewardj7cf4e6b2008-05-01 20:24:26 +00003546static MC_ReadResult is_mem_defined ( Addr a, SizeT len,
3547 /*OUT*/Addr* bad_addr,
3548 /*OUT*/UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003549{
nethercote451eae92004-11-02 13:06:32 +00003550 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003551 UWord vabits2;
njn25e49d8e72002-09-23 09:36:25 +00003552
njndbf7ca72006-03-31 11:57:59 +00003553 PROF_EVENT(64, "is_mem_defined");
3554 DEBUG("is_mem_defined\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003555
3556 if (otag) *otag = 0;
3557 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003558 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003559 PROF_EVENT(65, "is_mem_defined(loop)");
njn1d0825f2006-03-27 11:37:07 +00003560 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003561 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003562 // Error! Nb: Report addressability errors in preference to
3563 // definedness errors. And don't report definedeness errors unless
3564 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003565 if (bad_addr) {
3566 *bad_addr = a;
3567 }
3568 if (VA_BITS2_NOACCESS == vabits2) {
3569 return MC_AddrErr;
3570 }
3571 if (MC_(clo_mc_level) >= 2) {
3572 if (otag && MC_(clo_mc_level) == 3) {
3573 *otag = MC_(helperc_b_load1)( a );
3574 }
3575 return MC_ValueErr;
3576 }
njn25e49d8e72002-09-23 09:36:25 +00003577 }
3578 a++;
3579 }
nethercote8b76fe52004-11-08 19:20:09 +00003580 return MC_Ok;
njn25e49d8e72002-09-23 09:36:25 +00003581}
3582
3583
3584/* Check a zero-terminated ascii string. Tricky -- don't want to
3585 examine the actual bytes, to find the end, until we're sure it is
3586 safe to do so. */
3587
sewardj7cf4e6b2008-05-01 20:24:26 +00003588static Bool mc_is_defined_asciiz ( Addr a, Addr* bad_addr, UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003589{
njn1d0825f2006-03-27 11:37:07 +00003590 UWord vabits2;
3591
njndbf7ca72006-03-31 11:57:59 +00003592 PROF_EVENT(66, "mc_is_defined_asciiz");
3593 DEBUG("mc_is_defined_asciiz\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003594
3595 if (otag) *otag = 0;
3596 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003597 while (True) {
njndbf7ca72006-03-31 11:57:59 +00003598 PROF_EVENT(67, "mc_is_defined_asciiz(loop)");
njn1d0825f2006-03-27 11:37:07 +00003599 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003600 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003601 // Error! Nb: Report addressability errors in preference to
3602 // definedness errors. And don't report definedeness errors unless
3603 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003604 if (bad_addr) {
3605 *bad_addr = a;
3606 }
3607 if (VA_BITS2_NOACCESS == vabits2) {
3608 return MC_AddrErr;
3609 }
3610 if (MC_(clo_mc_level) >= 2) {
3611 if (otag && MC_(clo_mc_level) == 3) {
3612 *otag = MC_(helperc_b_load1)( a );
3613 }
3614 return MC_ValueErr;
3615 }
njn25e49d8e72002-09-23 09:36:25 +00003616 }
3617 /* Ok, a is safe to read. */
njn1d0825f2006-03-27 11:37:07 +00003618 if (* ((UChar*)a) == 0) {
sewardj45d94cc2005-04-20 14:44:11 +00003619 return MC_Ok;
njn1d0825f2006-03-27 11:37:07 +00003620 }
njn25e49d8e72002-09-23 09:36:25 +00003621 a++;
3622 }
3623}
3624
3625
3626/*------------------------------------------------------------*/
3627/*--- Memory event handlers ---*/
3628/*------------------------------------------------------------*/
3629
njn25e49d8e72002-09-23 09:36:25 +00003630static
njndbf7ca72006-03-31 11:57:59 +00003631void check_mem_is_addressable ( CorePart part, ThreadId tid, Char* s,
3632 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003633{
njn25e49d8e72002-09-23 09:36:25 +00003634 Addr bad_addr;
njndbf7ca72006-03-31 11:57:59 +00003635 Bool ok = is_mem_addressable ( base, size, &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003636
njn25e49d8e72002-09-23 09:36:25 +00003637 if (!ok) {
3638 switch (part) {
3639 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003640 MC_(record_memparam_error) ( tid, bad_addr,
3641 /*isAddrErr*/True, s, 0/*otag*/ );
njn25e49d8e72002-09-23 09:36:25 +00003642 break;
3643
njn25e49d8e72002-09-23 09:36:25 +00003644 case Vg_CoreSignal:
njn1dcee092009-02-24 03:07:37 +00003645 MC_(record_core_mem_error)( tid, s );
njn25e49d8e72002-09-23 09:36:25 +00003646 break;
3647
3648 default:
njndbf7ca72006-03-31 11:57:59 +00003649 VG_(tool_panic)("check_mem_is_addressable: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003650 }
3651 }
njn25e49d8e72002-09-23 09:36:25 +00003652}
3653
3654static
njndbf7ca72006-03-31 11:57:59 +00003655void check_mem_is_defined ( CorePart part, ThreadId tid, Char* s,
nethercote451eae92004-11-02 13:06:32 +00003656 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003657{
sewardj7cf4e6b2008-05-01 20:24:26 +00003658 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003659 Addr bad_addr;
sewardj7cf4e6b2008-05-01 20:24:26 +00003660 MC_ReadResult res = is_mem_defined ( base, size, &bad_addr, &otag );
sewardj45f4e7c2005-09-27 19:20:21 +00003661
nethercote8b76fe52004-11-08 19:20:09 +00003662 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003663 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj45f4e7c2005-09-27 19:20:21 +00003664
njn25e49d8e72002-09-23 09:36:25 +00003665 switch (part) {
3666 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003667 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3668 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003669 break;
3670
njnf76d27a2009-05-28 01:53:07 +00003671 case Vg_CoreSysCallArgInMem:
3672 MC_(record_regparam_error) ( tid, s, otag );
3673 break;
3674
njn25e49d8e72002-09-23 09:36:25 +00003675 /* If we're being asked to jump to a silly address, record an error
3676 message before potentially crashing the entire system. */
3677 case Vg_CoreTranslate:
sewardj7ce71662008-05-02 10:33:15 +00003678 MC_(record_jump_error)( tid, bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003679 break;
3680
3681 default:
njndbf7ca72006-03-31 11:57:59 +00003682 VG_(tool_panic)("check_mem_is_defined: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003683 }
3684 }
njn25e49d8e72002-09-23 09:36:25 +00003685}
3686
3687static
njndbf7ca72006-03-31 11:57:59 +00003688void check_mem_is_defined_asciiz ( CorePart part, ThreadId tid,
njn5c004e42002-11-18 11:04:50 +00003689 Char* s, Addr str )
njn25e49d8e72002-09-23 09:36:25 +00003690{
nethercote8b76fe52004-11-08 19:20:09 +00003691 MC_ReadResult res;
njn5ab96ac2005-05-08 02:59:50 +00003692 Addr bad_addr = 0; // shut GCC up
sewardj7cf4e6b2008-05-01 20:24:26 +00003693 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003694
njnca82cc02004-11-22 17:18:48 +00003695 tl_assert(part == Vg_CoreSysCall);
sewardj7cf4e6b2008-05-01 20:24:26 +00003696 res = mc_is_defined_asciiz ( (Addr)str, &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00003697 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003698 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj7ce71662008-05-02 10:33:15 +00003699 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3700 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003701 }
njn25e49d8e72002-09-23 09:36:25 +00003702}
3703
njn25e49d8e72002-09-23 09:36:25 +00003704static
njnf76d27a2009-05-28 01:53:07 +00003705void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
3706 ULong di_handle )
3707{
3708 if (rr || ww || xx)
3709 MC_(make_mem_defined)(a, len);
3710 else
3711 MC_(make_mem_noaccess)(a, len);
3712}
3713
3714static
sewardj9c606bd2008-09-18 18:12:50 +00003715void mc_new_mem_startup( Addr a, SizeT len,
3716 Bool rr, Bool ww, Bool xx, ULong di_handle )
njn25e49d8e72002-09-23 09:36:25 +00003717{
njnba7b4582006-09-21 15:59:30 +00003718 // Because code is defined, initialised variables get put in the data
3719 // segment and are defined, and uninitialised variables get put in the
3720 // bss segment and are auto-zeroed (and so defined).
3721 //
3722 // It's possible that there will be padding between global variables.
3723 // This will also be auto-zeroed, and marked as defined by Memcheck. If
3724 // a program uses it, Memcheck will not complain. This is arguably a
3725 // false negative, but it's a grey area -- the behaviour is defined (the
3726 // padding is zeroed) but it's probably not what the user intended. And
3727 // we can't avoid it.
njnf76d27a2009-05-28 01:53:07 +00003728 //
3729 // Note: we generally ignore RWX permissions, because we can't track them
3730 // without requiring more than one A bit which would slow things down a
3731 // lot. But on Darwin the 0th page is mapped but !R and !W and !X.
3732 // So we mark any such pages as "unaddressable".
barta0b6b2c2008-07-07 06:49:24 +00003733 DEBUG("mc_new_mem_startup(%#lx, %llu, rr=%u, ww=%u, xx=%u)\n",
njndbf7ca72006-03-31 11:57:59 +00003734 a, (ULong)len, rr, ww, xx);
njnf76d27a2009-05-28 01:53:07 +00003735 mc_new_mem_mmap(a, len, rr, ww, xx, di_handle);
njn25e49d8e72002-09-23 09:36:25 +00003736}
3737
njncf45fd42004-11-24 16:30:22 +00003738static
3739void mc_post_mem_write(CorePart part, ThreadId tid, Addr a, SizeT len)
3740{
njndbf7ca72006-03-31 11:57:59 +00003741 MC_(make_mem_defined)(a, len);
njncf45fd42004-11-24 16:30:22 +00003742}
njn25e49d8e72002-09-23 09:36:25 +00003743
sewardj45d94cc2005-04-20 14:44:11 +00003744
njn25e49d8e72002-09-23 09:36:25 +00003745/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00003746/*--- Register event handlers ---*/
3747/*------------------------------------------------------------*/
3748
sewardj7cf4e6b2008-05-01 20:24:26 +00003749/* Try and get a nonzero origin for the guest state section of thread
3750 tid characterised by (offset,size). Return 0 if nothing to show
3751 for it. */
3752static UInt mb_get_origin_for_guest_offset ( ThreadId tid,
3753 Int offset, SizeT size )
3754{
3755 Int sh2off;
3756 UChar area[6];
3757 UInt otag;
3758 sh2off = MC_(get_otrack_shadow_offset)( offset, size );
3759 if (sh2off == -1)
3760 return 0; /* This piece of guest state is not tracked */
3761 tl_assert(sh2off >= 0);
3762 tl_assert(0 == (sh2off % 4));
3763 area[0] = 0x31;
3764 area[5] = 0x27;
3765 VG_(get_shadow_regs_area)( tid, &area[1], 2/*shadowno*/,sh2off,4 );
3766 tl_assert(area[0] == 0x31);
3767 tl_assert(area[5] == 0x27);
3768 otag = *(UInt*)&area[1];
3769 return otag;
3770}
3771
3772
sewardj45d94cc2005-04-20 14:44:11 +00003773/* When some chunk of guest state is written, mark the corresponding
3774 shadow area as valid. This is used to initialise arbitrarily large
sewardj62eae5f2006-01-17 01:58:24 +00003775 chunks of guest state, hence the _SIZE value, which has to be as
3776 big as the biggest guest state.
sewardj45d94cc2005-04-20 14:44:11 +00003777*/
3778static void mc_post_reg_write ( CorePart part, ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003779 PtrdiffT offset, SizeT size)
njnd3040452003-05-19 15:04:06 +00003780{
sewardj05a46732006-10-17 01:28:10 +00003781# define MAX_REG_WRITE_SIZE 1408
cerion21082042005-12-06 19:07:08 +00003782 UChar area[MAX_REG_WRITE_SIZE];
3783 tl_assert(size <= MAX_REG_WRITE_SIZE);
njn1d0825f2006-03-27 11:37:07 +00003784 VG_(memset)(area, V_BITS8_DEFINED, size);
sewardj7cf4e6b2008-05-01 20:24:26 +00003785 VG_(set_shadow_regs_area)( tid, 1/*shadowNo*/,offset,size, area );
cerion21082042005-12-06 19:07:08 +00003786# undef MAX_REG_WRITE_SIZE
njnd3040452003-05-19 15:04:06 +00003787}
3788
sewardj45d94cc2005-04-20 14:44:11 +00003789static
3790void mc_post_reg_write_clientcall ( ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003791 PtrdiffT offset, SizeT size, Addr f)
njnd3040452003-05-19 15:04:06 +00003792{
njncf45fd42004-11-24 16:30:22 +00003793 mc_post_reg_write(/*dummy*/0, tid, offset, size);
njnd3040452003-05-19 15:04:06 +00003794}
3795
sewardj45d94cc2005-04-20 14:44:11 +00003796/* Look at the definedness of the guest's shadow state for
3797 [offset, offset+len). If any part of that is undefined, record
3798 a parameter error.
3799*/
3800static void mc_pre_reg_read ( CorePart part, ThreadId tid, Char* s,
njnc4431bf2009-01-15 21:29:24 +00003801 PtrdiffT offset, SizeT size)
nethercote8b76fe52004-11-08 19:20:09 +00003802{
sewardj45d94cc2005-04-20 14:44:11 +00003803 Int i;
3804 Bool bad;
sewardj7cf4e6b2008-05-01 20:24:26 +00003805 UInt otag;
sewardj45d94cc2005-04-20 14:44:11 +00003806
3807 UChar area[16];
3808 tl_assert(size <= 16);
3809
sewardj7cf4e6b2008-05-01 20:24:26 +00003810 VG_(get_shadow_regs_area)( tid, area, 1/*shadowNo*/,offset,size );
sewardj45d94cc2005-04-20 14:44:11 +00003811
3812 bad = False;
3813 for (i = 0; i < size; i++) {
njn1d0825f2006-03-27 11:37:07 +00003814 if (area[i] != V_BITS8_DEFINED) {
sewardj2c27f702005-05-03 18:19:05 +00003815 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00003816 break;
3817 }
nethercote8b76fe52004-11-08 19:20:09 +00003818 }
3819
sewardj7cf4e6b2008-05-01 20:24:26 +00003820 if (!bad)
3821 return;
3822
3823 /* We've found some undefinedness. See if we can also find an
3824 origin for it. */
3825 otag = mb_get_origin_for_guest_offset( tid, offset, size );
sewardj7ce71662008-05-02 10:33:15 +00003826 MC_(record_regparam_error) ( tid, s, otag );
nethercote8b76fe52004-11-08 19:20:09 +00003827}
njnd3040452003-05-19 15:04:06 +00003828
njn25e49d8e72002-09-23 09:36:25 +00003829
sewardj6cf40ff2005-04-20 22:31:26 +00003830/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00003831/*--- Functions called directly from generated code: ---*/
3832/*--- Load/store handlers. ---*/
sewardj6cf40ff2005-04-20 22:31:26 +00003833/*------------------------------------------------------------*/
3834
njn1d0825f2006-03-27 11:37:07 +00003835/* Types: LOADV32, LOADV16, LOADV8 are:
sewardj6cf40ff2005-04-20 22:31:26 +00003836 UWord fn ( Addr a )
3837 so they return 32-bits on 32-bit machines and 64-bits on
3838 64-bit machines. Addr has the same size as a host word.
3839
njn1d0825f2006-03-27 11:37:07 +00003840 LOADV64 is always ULong fn ( Addr a )
sewardj6cf40ff2005-04-20 22:31:26 +00003841
njn1d0825f2006-03-27 11:37:07 +00003842 Similarly for STOREV8, STOREV16, STOREV32, the supplied vbits
3843 are a UWord, and for STOREV64 they are a ULong.
sewardj6cf40ff2005-04-20 22:31:26 +00003844*/
3845
sewardj7244e712008-05-02 12:35:48 +00003846/* If any part of '_a' indicated by the mask is 1, either '_a' is not
3847 naturally '_sz/8'-aligned, or it exceeds the range covered by the
3848 primary map. This is all very tricky (and important!), so let's
3849 work through the maths by hand (below), *and* assert for these
3850 values at startup. */
3851#define MASK(_szInBytes) \
3852 ( ~((0x10000UL-(_szInBytes)) | ((N_PRIMARY_MAP-1) << 16)) )
3853
3854/* MASK only exists so as to define this macro. */
3855#define UNALIGNED_OR_HIGH(_a,_szInBits) \
3856 ((_a) & MASK((_szInBits>>3)))
3857
3858/* On a 32-bit machine:
3859
3860 N_PRIMARY_BITS == 16, so
3861 N_PRIMARY_MAP == 0x10000, so
3862 N_PRIMARY_MAP-1 == 0xFFFF, so
3863 (N_PRIMARY_MAP-1) << 16 == 0xFFFF0000, and so
3864
3865 MASK(1) = ~ ( (0x10000 - 1) | 0xFFFF0000 )
3866 = ~ ( 0xFFFF | 0xFFFF0000 )
3867 = ~ 0xFFFF'FFFF
3868 = 0
3869
3870 MASK(2) = ~ ( (0x10000 - 2) | 0xFFFF0000 )
3871 = ~ ( 0xFFFE | 0xFFFF0000 )
3872 = ~ 0xFFFF'FFFE
3873 = 1
3874
3875 MASK(4) = ~ ( (0x10000 - 4) | 0xFFFF0000 )
3876 = ~ ( 0xFFFC | 0xFFFF0000 )
3877 = ~ 0xFFFF'FFFC
3878 = 3
3879
3880 MASK(8) = ~ ( (0x10000 - 8) | 0xFFFF0000 )
3881 = ~ ( 0xFFF8 | 0xFFFF0000 )
3882 = ~ 0xFFFF'FFF8
3883 = 7
3884
3885 Hence in the 32-bit case, "a & MASK(1/2/4/8)" is a nonzero value
3886 precisely when a is not 1/2/4/8-bytes aligned. And obviously, for
3887 the 1-byte alignment case, it is always a zero value, since MASK(1)
3888 is zero. All as expected.
3889
3890 On a 64-bit machine, it's more complex, since we're testing
3891 simultaneously for misalignment and for the address being at or
3892 above 32G:
3893
3894 N_PRIMARY_BITS == 19, so
3895 N_PRIMARY_MAP == 0x80000, so
3896 N_PRIMARY_MAP-1 == 0x7FFFF, so
3897 (N_PRIMARY_MAP-1) << 16 == 0x7FFFF'0000, and so
3898
3899 MASK(1) = ~ ( (0x10000 - 1) | 0x7FFFF'0000 )
3900 = ~ ( 0xFFFF | 0x7FFFF'0000 )
3901 = ~ 0x7FFFF'FFFF
3902 = 0xFFFF'FFF8'0000'0000
3903
3904 MASK(2) = ~ ( (0x10000 - 2) | 0x7FFFF'0000 )
3905 = ~ ( 0xFFFE | 0x7FFFF'0000 )
3906 = ~ 0x7FFFF'FFFE
3907 = 0xFFFF'FFF8'0000'0001
3908
3909 MASK(4) = ~ ( (0x10000 - 4) | 0x7FFFF'0000 )
3910 = ~ ( 0xFFFC | 0x7FFFF'0000 )
3911 = ~ 0x7FFFF'FFFC
3912 = 0xFFFF'FFF8'0000'0003
3913
3914 MASK(8) = ~ ( (0x10000 - 8) | 0x7FFFF'0000 )
3915 = ~ ( 0xFFF8 | 0x7FFFF'0000 )
3916 = ~ 0x7FFFF'FFF8
3917 = 0xFFFF'FFF8'0000'0007
3918*/
njn1d0825f2006-03-27 11:37:07 +00003919
3920
sewardj95448072004-11-22 20:19:51 +00003921/* ------------------------ Size = 8 ------------------------ */
3922
njn1d0825f2006-03-27 11:37:07 +00003923static INLINE
3924ULong mc_LOADV64 ( Addr a, Bool isBigEndian )
3925{
njn1d0825f2006-03-27 11:37:07 +00003926 PROF_EVENT(200, "mc_LOADV64");
3927
3928#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003929 return mc_LOADVn_slow( a, 64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003930#else
njneccf7c02009-01-19 23:42:45 +00003931 {
3932 UWord sm_off16, vabits16;
3933 SecMap* sm;
sewardjf9d81612005-04-23 23:25:49 +00003934
njneccf7c02009-01-19 23:42:45 +00003935 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
3936 PROF_EVENT(201, "mc_LOADV64-slow1");
3937 return (ULong)mc_LOADVn_slow( a, 64, isBigEndian );
3938 }
njn1d0825f2006-03-27 11:37:07 +00003939
njneccf7c02009-01-19 23:42:45 +00003940 sm = get_secmap_for_reading_low(a);
3941 sm_off16 = SM_OFF_16(a);
3942 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3943
3944 // Handle common case quickly: a is suitably aligned, is mapped, and
3945 // addressible.
3946 // Convert V bits from compact memory form to expanded register form.
3947 if (LIKELY(vabits16 == VA_BITS16_DEFINED)) {
3948 return V_BITS64_DEFINED;
3949 } else if (LIKELY(vabits16 == VA_BITS16_UNDEFINED)) {
3950 return V_BITS64_UNDEFINED;
3951 } else {
3952 /* Slow case: the 8 bytes are not all-defined or all-undefined. */
3953 PROF_EVENT(202, "mc_LOADV64-slow2");
3954 return mc_LOADVn_slow( a, 64, isBigEndian );
3955 }
njn1d0825f2006-03-27 11:37:07 +00003956 }
3957#endif
3958}
3959
3960VG_REGPARM(1) ULong MC_(helperc_LOADV64be) ( Addr a )
3961{
3962 return mc_LOADV64(a, True);
3963}
3964VG_REGPARM(1) ULong MC_(helperc_LOADV64le) ( Addr a )
3965{
3966 return mc_LOADV64(a, False);
3967}
sewardjf9d81612005-04-23 23:25:49 +00003968
sewardjf9d81612005-04-23 23:25:49 +00003969
njn1d0825f2006-03-27 11:37:07 +00003970static INLINE
njn4cf530b2006-04-06 13:33:48 +00003971void mc_STOREV64 ( Addr a, ULong vbits64, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00003972{
njn1d0825f2006-03-27 11:37:07 +00003973 PROF_EVENT(210, "mc_STOREV64");
3974
3975#ifndef PERF_FAST_STOREV
3976 // XXX: this slow case seems to be marginally faster than the fast case!
3977 // Investigate further.
njn4cf530b2006-04-06 13:33:48 +00003978 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003979#else
njn1d0825f2006-03-27 11:37:07 +00003980 {
njneccf7c02009-01-19 23:42:45 +00003981 UWord sm_off16, vabits16;
3982 SecMap* sm;
3983
3984 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
3985 PROF_EVENT(211, "mc_STOREV64-slow1");
3986 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
3987 return;
3988 }
3989
3990 sm = get_secmap_for_reading_low(a);
3991 sm_off16 = SM_OFF_16(a);
3992 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3993
3994 if (LIKELY( !is_distinguished_sm(sm) &&
3995 (VA_BITS16_DEFINED == vabits16 ||
3996 VA_BITS16_UNDEFINED == vabits16) ))
3997 {
3998 /* Handle common case quickly: a is suitably aligned, */
3999 /* is mapped, and is addressible. */
4000 // Convert full V-bits in register to compact 2-bit form.
4001 if (V_BITS64_DEFINED == vbits64) {
4002 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
4003 } else if (V_BITS64_UNDEFINED == vbits64) {
4004 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
4005 } else {
4006 /* Slow but general case -- writing partially defined bytes. */
4007 PROF_EVENT(212, "mc_STOREV64-slow2");
4008 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
4009 }
njn1d0825f2006-03-27 11:37:07 +00004010 } else {
njneccf7c02009-01-19 23:42:45 +00004011 /* Slow but general case. */
4012 PROF_EVENT(213, "mc_STOREV64-slow3");
njn4cf530b2006-04-06 13:33:48 +00004013 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004014 }
njn1d0825f2006-03-27 11:37:07 +00004015 }
4016#endif
4017}
4018
njn4cf530b2006-04-06 13:33:48 +00004019VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00004020{
njn4cf530b2006-04-06 13:33:48 +00004021 mc_STOREV64(a, vbits64, True);
njn1d0825f2006-03-27 11:37:07 +00004022}
njn4cf530b2006-04-06 13:33:48 +00004023VG_REGPARM(1) void MC_(helperc_STOREV64le) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00004024{
njn4cf530b2006-04-06 13:33:48 +00004025 mc_STOREV64(a, vbits64, False);
njn1d0825f2006-03-27 11:37:07 +00004026}
sewardj95448072004-11-22 20:19:51 +00004027
sewardj95448072004-11-22 20:19:51 +00004028
4029/* ------------------------ Size = 4 ------------------------ */
4030
njn1d0825f2006-03-27 11:37:07 +00004031static INLINE
4032UWord mc_LOADV32 ( Addr a, Bool isBigEndian )
4033{
njn1d0825f2006-03-27 11:37:07 +00004034 PROF_EVENT(220, "mc_LOADV32");
4035
4036#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004037 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004038#else
njneccf7c02009-01-19 23:42:45 +00004039 {
4040 UWord sm_off, vabits8;
4041 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004042
njneccf7c02009-01-19 23:42:45 +00004043 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
4044 PROF_EVENT(221, "mc_LOADV32-slow1");
4045 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
4046 }
njn1d0825f2006-03-27 11:37:07 +00004047
njneccf7c02009-01-19 23:42:45 +00004048 sm = get_secmap_for_reading_low(a);
4049 sm_off = SM_OFF(a);
4050 vabits8 = sm->vabits8[sm_off];
4051
4052 // Handle common case quickly: a is suitably aligned, is mapped, and the
4053 // entire word32 it lives in is addressible.
4054 // Convert V bits from compact memory form to expanded register form.
4055 // For 64-bit platforms, set the high 32 bits of retval to 1 (undefined).
4056 // Almost certainly not necessary, but be paranoid.
4057 if (LIKELY(vabits8 == VA_BITS8_DEFINED)) {
4058 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
4059 } else if (LIKELY(vabits8 == VA_BITS8_UNDEFINED)) {
4060 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
4061 } else {
4062 /* Slow case: the 4 bytes are not all-defined or all-undefined. */
4063 PROF_EVENT(222, "mc_LOADV32-slow2");
4064 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
4065 }
njn1d0825f2006-03-27 11:37:07 +00004066 }
4067#endif
4068}
4069
4070VG_REGPARM(1) UWord MC_(helperc_LOADV32be) ( Addr a )
4071{
4072 return mc_LOADV32(a, True);
4073}
4074VG_REGPARM(1) UWord MC_(helperc_LOADV32le) ( Addr a )
4075{
4076 return mc_LOADV32(a, False);
4077}
sewardjc1a2cda2005-04-21 17:34:00 +00004078
sewardjc1a2cda2005-04-21 17:34:00 +00004079
njn1d0825f2006-03-27 11:37:07 +00004080static INLINE
njn4cf530b2006-04-06 13:33:48 +00004081void mc_STOREV32 ( Addr a, UWord vbits32, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004082{
njn1d0825f2006-03-27 11:37:07 +00004083 PROF_EVENT(230, "mc_STOREV32");
4084
4085#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004086 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004087#else
njneccf7c02009-01-19 23:42:45 +00004088 {
4089 UWord sm_off, vabits8;
4090 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004091
njneccf7c02009-01-19 23:42:45 +00004092 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
4093 PROF_EVENT(231, "mc_STOREV32-slow1");
4094 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004095 return;
njneccf7c02009-01-19 23:42:45 +00004096 }
4097
4098 sm = get_secmap_for_reading_low(a);
4099 sm_off = SM_OFF(a);
4100 vabits8 = sm->vabits8[sm_off];
4101
4102 // Cleverness: sometimes we don't have to write the shadow memory at
4103 // all, if we can tell that what we want to write is the same as what is
4104 // already there. The 64/16/8 bit cases also have cleverness at this
4105 // point, but it works a little differently to the code below.
4106 if (V_BITS32_DEFINED == vbits32) {
4107 if (vabits8 == (UInt)VA_BITS8_DEFINED) {
4108 return;
4109 } else if (!is_distinguished_sm(sm) && VA_BITS8_UNDEFINED == vabits8) {
4110 sm->vabits8[sm_off] = (UInt)VA_BITS8_DEFINED;
4111 } else {
4112 // not defined/undefined, or distinguished and changing state
4113 PROF_EVENT(232, "mc_STOREV32-slow2");
4114 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
4115 }
4116 } else if (V_BITS32_UNDEFINED == vbits32) {
4117 if (vabits8 == (UInt)VA_BITS8_UNDEFINED) {
4118 return;
4119 } else if (!is_distinguished_sm(sm) && VA_BITS8_DEFINED == vabits8) {
4120 sm->vabits8[sm_off] = (UInt)VA_BITS8_UNDEFINED;
4121 } else {
4122 // not defined/undefined, or distinguished and changing state
4123 PROF_EVENT(233, "mc_STOREV32-slow3");
4124 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
4125 }
njn1d0825f2006-03-27 11:37:07 +00004126 } else {
njneccf7c02009-01-19 23:42:45 +00004127 // Partially defined word
4128 PROF_EVENT(234, "mc_STOREV32-slow4");
njn4cf530b2006-04-06 13:33:48 +00004129 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004130 }
njn1d0825f2006-03-27 11:37:07 +00004131 }
njn1d0825f2006-03-27 11:37:07 +00004132#endif
4133}
4134
njn4cf530b2006-04-06 13:33:48 +00004135VG_REGPARM(2) void MC_(helperc_STOREV32be) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004136{
njn4cf530b2006-04-06 13:33:48 +00004137 mc_STOREV32(a, vbits32, True);
njn1d0825f2006-03-27 11:37:07 +00004138}
njn4cf530b2006-04-06 13:33:48 +00004139VG_REGPARM(2) void MC_(helperc_STOREV32le) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004140{
njn4cf530b2006-04-06 13:33:48 +00004141 mc_STOREV32(a, vbits32, False);
njn1d0825f2006-03-27 11:37:07 +00004142}
njn25e49d8e72002-09-23 09:36:25 +00004143
njn25e49d8e72002-09-23 09:36:25 +00004144
sewardj95448072004-11-22 20:19:51 +00004145/* ------------------------ Size = 2 ------------------------ */
4146
njn1d0825f2006-03-27 11:37:07 +00004147static INLINE
4148UWord mc_LOADV16 ( Addr a, Bool isBigEndian )
4149{
njn1d0825f2006-03-27 11:37:07 +00004150 PROF_EVENT(240, "mc_LOADV16");
4151
4152#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004153 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004154#else
njneccf7c02009-01-19 23:42:45 +00004155 {
4156 UWord sm_off, vabits8;
4157 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004158
njneccf7c02009-01-19 23:42:45 +00004159 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
4160 PROF_EVENT(241, "mc_LOADV16-slow1");
njn45e81252006-03-28 12:35:08 +00004161 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004162 }
njneccf7c02009-01-19 23:42:45 +00004163
4164 sm = get_secmap_for_reading_low(a);
4165 sm_off = SM_OFF(a);
4166 vabits8 = sm->vabits8[sm_off];
4167 // Handle common case quickly: a is suitably aligned, is mapped, and is
4168 // addressible.
4169 // Convert V bits from compact memory form to expanded register form
4170 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS16_DEFINED; }
4171 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS16_UNDEFINED; }
4172 else {
4173 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
4174 // the two sub-bytes.
4175 UChar vabits4 = extract_vabits4_from_vabits8(a, vabits8);
4176 if (vabits4 == VA_BITS4_DEFINED ) { return V_BITS16_DEFINED; }
4177 else if (vabits4 == VA_BITS4_UNDEFINED) { return V_BITS16_UNDEFINED; }
4178 else {
4179 /* Slow case: the two bytes are not all-defined or all-undefined. */
4180 PROF_EVENT(242, "mc_LOADV16-slow2");
4181 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
4182 }
4183 }
njn1d0825f2006-03-27 11:37:07 +00004184 }
4185#endif
4186}
4187
4188VG_REGPARM(1) UWord MC_(helperc_LOADV16be) ( Addr a )
4189{
4190 return mc_LOADV16(a, True);
4191}
4192VG_REGPARM(1) UWord MC_(helperc_LOADV16le) ( Addr a )
4193{
4194 return mc_LOADV16(a, False);
4195}
sewardjc1a2cda2005-04-21 17:34:00 +00004196
sewardjc1a2cda2005-04-21 17:34:00 +00004197
njn1d0825f2006-03-27 11:37:07 +00004198static INLINE
njn4cf530b2006-04-06 13:33:48 +00004199void mc_STOREV16 ( Addr a, UWord vbits16, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004200{
njn1d0825f2006-03-27 11:37:07 +00004201 PROF_EVENT(250, "mc_STOREV16");
4202
4203#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004204 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004205#else
njn1d0825f2006-03-27 11:37:07 +00004206 {
njneccf7c02009-01-19 23:42:45 +00004207 UWord sm_off, vabits8;
4208 SecMap* sm;
4209
4210 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
4211 PROF_EVENT(251, "mc_STOREV16-slow1");
4212 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
4213 return;
4214 }
4215
4216 sm = get_secmap_for_reading_low(a);
4217 sm_off = SM_OFF(a);
4218 vabits8 = sm->vabits8[sm_off];
4219 if (LIKELY( !is_distinguished_sm(sm) &&
4220 (VA_BITS8_DEFINED == vabits8 ||
4221 VA_BITS8_UNDEFINED == vabits8) ))
4222 {
4223 /* Handle common case quickly: a is suitably aligned, */
4224 /* is mapped, and is addressible. */
4225 // Convert full V-bits in register to compact 2-bit form.
4226 if (V_BITS16_DEFINED == vbits16) {
4227 insert_vabits4_into_vabits8( a, VA_BITS4_DEFINED ,
4228 &(sm->vabits8[sm_off]) );
4229 } else if (V_BITS16_UNDEFINED == vbits16) {
4230 insert_vabits4_into_vabits8( a, VA_BITS4_UNDEFINED,
4231 &(sm->vabits8[sm_off]) );
4232 } else {
4233 /* Slow but general case -- writing partially defined bytes. */
4234 PROF_EVENT(252, "mc_STOREV16-slow2");
4235 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
4236 }
njn1d0825f2006-03-27 11:37:07 +00004237 } else {
njneccf7c02009-01-19 23:42:45 +00004238 /* Slow but general case. */
4239 PROF_EVENT(253, "mc_STOREV16-slow3");
njn4cf530b2006-04-06 13:33:48 +00004240 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004241 }
njn1d0825f2006-03-27 11:37:07 +00004242 }
4243#endif
4244}
njn25e49d8e72002-09-23 09:36:25 +00004245
njn4cf530b2006-04-06 13:33:48 +00004246VG_REGPARM(2) void MC_(helperc_STOREV16be) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004247{
njn4cf530b2006-04-06 13:33:48 +00004248 mc_STOREV16(a, vbits16, True);
njn1d0825f2006-03-27 11:37:07 +00004249}
njn4cf530b2006-04-06 13:33:48 +00004250VG_REGPARM(2) void MC_(helperc_STOREV16le) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004251{
njn4cf530b2006-04-06 13:33:48 +00004252 mc_STOREV16(a, vbits16, False);
njn1d0825f2006-03-27 11:37:07 +00004253}
sewardj5d28efc2005-04-21 22:16:29 +00004254
njn25e49d8e72002-09-23 09:36:25 +00004255
sewardj95448072004-11-22 20:19:51 +00004256/* ------------------------ Size = 1 ------------------------ */
sewardj8cf88b72005-07-08 01:29:33 +00004257/* Note: endianness is irrelevant for size == 1 */
sewardj95448072004-11-22 20:19:51 +00004258
njnaf839f52005-06-23 03:27:57 +00004259VG_REGPARM(1)
njn1d0825f2006-03-27 11:37:07 +00004260UWord MC_(helperc_LOADV8) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00004261{
njn1d0825f2006-03-27 11:37:07 +00004262 PROF_EVENT(260, "mc_LOADV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004263
njn1d0825f2006-03-27 11:37:07 +00004264#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004265 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004266#else
njneccf7c02009-01-19 23:42:45 +00004267 {
4268 UWord sm_off, vabits8;
4269 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004270
njneccf7c02009-01-19 23:42:45 +00004271 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
4272 PROF_EVENT(261, "mc_LOADV8-slow1");
njn45e81252006-03-28 12:35:08 +00004273 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004274 }
njneccf7c02009-01-19 23:42:45 +00004275
4276 sm = get_secmap_for_reading_low(a);
4277 sm_off = SM_OFF(a);
4278 vabits8 = sm->vabits8[sm_off];
4279 // Convert V bits from compact memory form to expanded register form
4280 // Handle common case quickly: a is mapped, and the entire
4281 // word32 it lives in is addressible.
4282 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS8_DEFINED; }
4283 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS8_UNDEFINED; }
4284 else {
4285 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
4286 // the single byte.
4287 UChar vabits2 = extract_vabits2_from_vabits8(a, vabits8);
4288 if (vabits2 == VA_BITS2_DEFINED ) { return V_BITS8_DEFINED; }
4289 else if (vabits2 == VA_BITS2_UNDEFINED) { return V_BITS8_UNDEFINED; }
4290 else {
4291 /* Slow case: the byte is not all-defined or all-undefined. */
4292 PROF_EVENT(262, "mc_LOADV8-slow2");
4293 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
4294 }
4295 }
sewardjc1a2cda2005-04-21 17:34:00 +00004296 }
njn1d0825f2006-03-27 11:37:07 +00004297#endif
njn25e49d8e72002-09-23 09:36:25 +00004298}
4299
sewardjc1a2cda2005-04-21 17:34:00 +00004300
njnaf839f52005-06-23 03:27:57 +00004301VG_REGPARM(2)
njn4cf530b2006-04-06 13:33:48 +00004302void MC_(helperc_STOREV8) ( Addr a, UWord vbits8 )
njn25e49d8e72002-09-23 09:36:25 +00004303{
njn1d0825f2006-03-27 11:37:07 +00004304 PROF_EVENT(270, "mc_STOREV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004305
njn1d0825f2006-03-27 11:37:07 +00004306#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004307 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004308#else
njn1d0825f2006-03-27 11:37:07 +00004309 {
njneccf7c02009-01-19 23:42:45 +00004310 UWord sm_off, vabits8;
4311 SecMap* sm;
4312
4313 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
4314 PROF_EVENT(271, "mc_STOREV8-slow1");
4315 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
4316 return;
4317 }
4318
4319 sm = get_secmap_for_reading_low(a);
4320 sm_off = SM_OFF(a);
4321 vabits8 = sm->vabits8[sm_off];
4322 if (LIKELY
4323 ( !is_distinguished_sm(sm) &&
4324 ( (VA_BITS8_DEFINED == vabits8 || VA_BITS8_UNDEFINED == vabits8)
4325 || (VA_BITS2_NOACCESS != extract_vabits2_from_vabits8(a, vabits8))
4326 )
4327 )
4328 )
4329 {
4330 /* Handle common case quickly: a is mapped, the entire word32 it
4331 lives in is addressible. */
4332 // Convert full V-bits in register to compact 2-bit form.
4333 if (V_BITS8_DEFINED == vbits8) {
4334 insert_vabits2_into_vabits8( a, VA_BITS2_DEFINED,
4335 &(sm->vabits8[sm_off]) );
4336 } else if (V_BITS8_UNDEFINED == vbits8) {
4337 insert_vabits2_into_vabits8( a, VA_BITS2_UNDEFINED,
4338 &(sm->vabits8[sm_off]) );
4339 } else {
4340 /* Slow but general case -- writing partially defined bytes. */
4341 PROF_EVENT(272, "mc_STOREV8-slow2");
4342 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
4343 }
njn1d0825f2006-03-27 11:37:07 +00004344 } else {
njneccf7c02009-01-19 23:42:45 +00004345 /* Slow but general case. */
4346 PROF_EVENT(273, "mc_STOREV8-slow3");
njn4cf530b2006-04-06 13:33:48 +00004347 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004348 }
sewardjc1a2cda2005-04-21 17:34:00 +00004349 }
njn1d0825f2006-03-27 11:37:07 +00004350#endif
njn25e49d8e72002-09-23 09:36:25 +00004351}
4352
4353
sewardjc859fbf2005-04-22 21:10:28 +00004354/*------------------------------------------------------------*/
4355/*--- Functions called directly from generated code: ---*/
4356/*--- Value-check failure handlers. ---*/
4357/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004358
sewardj7cf4e6b2008-05-01 20:24:26 +00004359/* Call these ones when an origin is available ... */
4360VG_REGPARM(1)
4361void MC_(helperc_value_check0_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004362 MC_(record_cond_error) ( VG_(get_running_tid)(), (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004363}
4364
sewardj7cf4e6b2008-05-01 20:24:26 +00004365VG_REGPARM(1)
4366void MC_(helperc_value_check1_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004367 MC_(record_value_error) ( VG_(get_running_tid)(), 1, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004368}
4369
sewardj7cf4e6b2008-05-01 20:24:26 +00004370VG_REGPARM(1)
4371void MC_(helperc_value_check4_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004372 MC_(record_value_error) ( VG_(get_running_tid)(), 4, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004373}
4374
sewardj7cf4e6b2008-05-01 20:24:26 +00004375VG_REGPARM(1)
4376void MC_(helperc_value_check8_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004377 MC_(record_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin );
sewardj11bcc4e2005-04-23 22:38:38 +00004378}
4379
sewardj7cf4e6b2008-05-01 20:24:26 +00004380VG_REGPARM(2)
4381void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004382 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin );
sewardj7cf4e6b2008-05-01 20:24:26 +00004383}
4384
4385/* ... and these when an origin isn't available. */
4386
4387VG_REGPARM(0)
4388void MC_(helperc_value_check0_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004389 MC_(record_cond_error) ( VG_(get_running_tid)(), 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004390}
4391
4392VG_REGPARM(0)
4393void MC_(helperc_value_check1_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004394 MC_(record_value_error) ( VG_(get_running_tid)(), 1, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004395}
4396
4397VG_REGPARM(0)
4398void MC_(helperc_value_check4_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004399 MC_(record_value_error) ( VG_(get_running_tid)(), 4, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004400}
4401
4402VG_REGPARM(0)
4403void MC_(helperc_value_check8_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004404 MC_(record_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004405}
4406
4407VG_REGPARM(1)
4408void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) {
sewardj7ce71662008-05-02 10:33:15 +00004409 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ );
sewardj95448072004-11-22 20:19:51 +00004410}
4411
njn25e49d8e72002-09-23 09:36:25 +00004412
sewardjc2c12c22006-03-08 13:20:09 +00004413/*------------------------------------------------------------*/
4414/*--- Metadata get/set functions, for client requests. ---*/
4415/*------------------------------------------------------------*/
4416
njn1d0825f2006-03-27 11:37:07 +00004417// Nb: this expands the V+A bits out into register-form V bits, even though
4418// they're in memory. This is for backward compatibility, and because it's
4419// probably what the user wants.
4420
4421/* Copy Vbits from/to address 'a'. Returns: 1 == OK, 2 == alignment
sewardjc2c12c22006-03-08 13:20:09 +00004422 error [no longer used], 3 == addressing error. */
njn718d3b12006-12-16 00:54:12 +00004423/* Nb: We used to issue various definedness/addressability errors from here,
4424 but we took them out because they ranged from not-very-helpful to
4425 downright annoying, and they complicated the error data structures. */
sewardjc2c12c22006-03-08 13:20:09 +00004426static Int mc_get_or_set_vbits_for_client (
njn1d0825f2006-03-27 11:37:07 +00004427 Addr a,
4428 Addr vbits,
4429 SizeT szB,
sewardjc2c12c22006-03-08 13:20:09 +00004430 Bool setting /* True <=> set vbits, False <=> get vbits */
4431)
4432{
sewardjc2c12c22006-03-08 13:20:09 +00004433 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00004434 Bool ok;
4435 UChar vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004436
njn1d0825f2006-03-27 11:37:07 +00004437 /* Check that arrays are addressible before doing any getting/setting. */
4438 for (i = 0; i < szB; i++) {
njn718d3b12006-12-16 00:54:12 +00004439 if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
4440 VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
njn1d0825f2006-03-27 11:37:07 +00004441 return 3;
sewardjc2c12c22006-03-08 13:20:09 +00004442 }
4443 }
njn1d0825f2006-03-27 11:37:07 +00004444
sewardjc2c12c22006-03-08 13:20:09 +00004445 /* Do the copy */
4446 if (setting) {
njn1d0825f2006-03-27 11:37:07 +00004447 /* setting */
4448 for (i = 0; i < szB; i++) {
4449 ok = set_vbits8(a + i, ((UChar*)vbits)[i]);
4450 tl_assert(ok);
sewardjc2c12c22006-03-08 13:20:09 +00004451 }
4452 } else {
4453 /* getting */
njn1d0825f2006-03-27 11:37:07 +00004454 for (i = 0; i < szB; i++) {
4455 ok = get_vbits8(a + i, &vbits8);
4456 tl_assert(ok);
njn1d0825f2006-03-27 11:37:07 +00004457 ((UChar*)vbits)[i] = vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004458 }
4459 // The bytes in vbits[] have now been set, so mark them as such.
njndbf7ca72006-03-31 11:57:59 +00004460 MC_(make_mem_defined)(vbits, szB);
njn1d0825f2006-03-27 11:37:07 +00004461 }
sewardjc2c12c22006-03-08 13:20:09 +00004462
4463 return 1;
4464}
sewardj05fe85e2005-04-27 22:46:36 +00004465
4466
4467/*------------------------------------------------------------*/
4468/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
4469/*------------------------------------------------------------*/
4470
4471/* For the memory leak detector, say whether an entire 64k chunk of
4472 address space is possibly in use, or not. If in doubt return
4473 True.
4474*/
njn8225cc02009-03-09 22:52:24 +00004475Bool MC_(is_within_valid_secondary) ( Addr a )
sewardj05fe85e2005-04-27 22:46:36 +00004476{
4477 SecMap* sm = maybe_get_secmap_for ( a );
sewardj05a46732006-10-17 01:28:10 +00004478 if (sm == NULL || sm == &sm_distinguished[SM_DIST_NOACCESS]
sewardj7ce71662008-05-02 10:33:15 +00004479 || MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004480 /* Definitely not in use. */
4481 return False;
4482 } else {
4483 return True;
4484 }
4485}
4486
4487
4488/* For the memory leak detector, say whether or not a given word
4489 address is to be regarded as valid. */
njn8225cc02009-03-09 22:52:24 +00004490Bool MC_(is_valid_aligned_word) ( Addr a )
sewardj05fe85e2005-04-27 22:46:36 +00004491{
4492 tl_assert(sizeof(UWord) == 4 || sizeof(UWord) == 8);
njn8225cc02009-03-09 22:52:24 +00004493 tl_assert(VG_IS_WORD_ALIGNED(a));
sewardj7cf4e6b2008-05-01 20:24:26 +00004494 if (is_mem_defined( a, sizeof(UWord), NULL, NULL) == MC_Ok
sewardj7ce71662008-05-02 10:33:15 +00004495 && !MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004496 return True;
4497 } else {
4498 return False;
4499 }
4500}
sewardja4495682002-10-21 07:29:59 +00004501
4502
sewardjc859fbf2005-04-22 21:10:28 +00004503/*------------------------------------------------------------*/
4504/*--- Initialisation ---*/
4505/*------------------------------------------------------------*/
4506
4507static void init_shadow_memory ( void )
4508{
4509 Int i;
4510 SecMap* sm;
4511
njn1d0825f2006-03-27 11:37:07 +00004512 tl_assert(V_BIT_UNDEFINED == 1);
4513 tl_assert(V_BIT_DEFINED == 0);
4514 tl_assert(V_BITS8_UNDEFINED == 0xFF);
4515 tl_assert(V_BITS8_DEFINED == 0);
4516
sewardjc859fbf2005-04-22 21:10:28 +00004517 /* Build the 3 distinguished secondaries */
sewardjc859fbf2005-04-22 21:10:28 +00004518 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004519 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_NOACCESS;
sewardjc859fbf2005-04-22 21:10:28 +00004520
njndbf7ca72006-03-31 11:57:59 +00004521 sm = &sm_distinguished[SM_DIST_UNDEFINED];
4522 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_UNDEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004523
njndbf7ca72006-03-31 11:57:59 +00004524 sm = &sm_distinguished[SM_DIST_DEFINED];
4525 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_DEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004526
4527 /* Set up the primary map. */
4528 /* These entries gradually get overwritten as the used address
4529 space expands. */
4530 for (i = 0; i < N_PRIMARY_MAP; i++)
4531 primary_map[i] = &sm_distinguished[SM_DIST_NOACCESS];
4532
sewardj05a46732006-10-17 01:28:10 +00004533 /* Auxiliary primary maps */
4534 init_auxmap_L1_L2();
4535
sewardjc859fbf2005-04-22 21:10:28 +00004536 /* auxmap_size = auxmap_used = 0;
4537 no ... these are statically initialised */
njn1d0825f2006-03-27 11:37:07 +00004538
4539 /* Secondary V bit table */
4540 secVBitTable = createSecVBitTable();
sewardjc859fbf2005-04-22 21:10:28 +00004541}
4542
4543
4544/*------------------------------------------------------------*/
4545/*--- Sanity check machinery (permanently engaged) ---*/
4546/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004547
njn51d827b2005-05-09 01:02:08 +00004548static Bool mc_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004549{
sewardj23eb2fd2005-04-22 16:29:19 +00004550 n_sanity_cheap++;
sewardjc1a2cda2005-04-21 17:34:00 +00004551 PROF_EVENT(490, "cheap_sanity_check");
sewardj7cf4e6b2008-05-01 20:24:26 +00004552 /* Check for sane operating level */
4553 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4554 return False;
4555 /* nothing else useful we can rapidly check */
jseward9800fd32004-01-04 23:08:04 +00004556 return True;
njn25e49d8e72002-09-23 09:36:25 +00004557}
4558
njn51d827b2005-05-09 01:02:08 +00004559static Bool mc_expensive_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004560{
sewardj05a46732006-10-17 01:28:10 +00004561 Int i;
4562 Word n_secmaps_found;
sewardj45d94cc2005-04-20 14:44:11 +00004563 SecMap* sm;
sewardj05a46732006-10-17 01:28:10 +00004564 HChar* errmsg;
sewardj23eb2fd2005-04-22 16:29:19 +00004565 Bool bad = False;
njn25e49d8e72002-09-23 09:36:25 +00004566
sewardj05a46732006-10-17 01:28:10 +00004567 if (0) VG_(printf)("expensive sanity check\n");
4568 if (0) return True;
4569
sewardj23eb2fd2005-04-22 16:29:19 +00004570 n_sanity_expensive++;
sewardjc1a2cda2005-04-21 17:34:00 +00004571 PROF_EVENT(491, "expensive_sanity_check");
4572
sewardj7cf4e6b2008-05-01 20:24:26 +00004573 /* Check for sane operating level */
4574 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4575 return False;
4576
njn1d0825f2006-03-27 11:37:07 +00004577 /* Check that the 3 distinguished SMs are still as they should be. */
njn25e49d8e72002-09-23 09:36:25 +00004578
njndbf7ca72006-03-31 11:57:59 +00004579 /* Check noaccess DSM. */
sewardj45d94cc2005-04-20 14:44:11 +00004580 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004581 for (i = 0; i < SM_CHUNKS; i++)
4582 if (sm->vabits8[i] != VA_BITS8_NOACCESS)
sewardj23eb2fd2005-04-22 16:29:19 +00004583 bad = True;
njn25e49d8e72002-09-23 09:36:25 +00004584
njndbf7ca72006-03-31 11:57:59 +00004585 /* Check undefined DSM. */
4586 sm = &sm_distinguished[SM_DIST_UNDEFINED];
njn1d0825f2006-03-27 11:37:07 +00004587 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004588 if (sm->vabits8[i] != VA_BITS8_UNDEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004589 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004590
njndbf7ca72006-03-31 11:57:59 +00004591 /* Check defined DSM. */
4592 sm = &sm_distinguished[SM_DIST_DEFINED];
njn1d0825f2006-03-27 11:37:07 +00004593 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004594 if (sm->vabits8[i] != VA_BITS8_DEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004595 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004596
sewardj23eb2fd2005-04-22 16:29:19 +00004597 if (bad) {
4598 VG_(printf)("memcheck expensive sanity: "
4599 "distinguished_secondaries have changed\n");
4600 return False;
4601 }
4602
njn1d0825f2006-03-27 11:37:07 +00004603 /* If we're not checking for undefined value errors, the secondary V bit
4604 * table should be empty. */
sewardj7cf4e6b2008-05-01 20:24:26 +00004605 if (MC_(clo_mc_level) == 1) {
njne2a9ad32007-09-17 05:30:48 +00004606 if (0 != VG_(OSetGen_Size)(secVBitTable))
njn1d0825f2006-03-27 11:37:07 +00004607 return False;
4608 }
4609
sewardj05a46732006-10-17 01:28:10 +00004610 /* check the auxiliary maps, very thoroughly */
4611 n_secmaps_found = 0;
4612 errmsg = check_auxmap_L1_L2_sanity( &n_secmaps_found );
4613 if (errmsg) {
4614 VG_(printf)("memcheck expensive sanity, auxmaps:\n\t%s", errmsg);
sewardj23eb2fd2005-04-22 16:29:19 +00004615 return False;
4616 }
4617
sewardj05a46732006-10-17 01:28:10 +00004618 /* n_secmaps_found is now the number referred to by the auxiliary
4619 primary map. Now add on the ones referred to by the main
4620 primary map. */
sewardj23eb2fd2005-04-22 16:29:19 +00004621 for (i = 0; i < N_PRIMARY_MAP; i++) {
sewardj05a46732006-10-17 01:28:10 +00004622 if (primary_map[i] == NULL) {
sewardj23eb2fd2005-04-22 16:29:19 +00004623 bad = True;
4624 } else {
sewardj05a46732006-10-17 01:28:10 +00004625 if (!is_distinguished_sm(primary_map[i]))
sewardj23eb2fd2005-04-22 16:29:19 +00004626 n_secmaps_found++;
4627 }
4628 }
4629
sewardj05a46732006-10-17 01:28:10 +00004630 /* check that the number of secmaps issued matches the number that
4631 are reachable (iow, no secmap leaks) */
njn1d0825f2006-03-27 11:37:07 +00004632 if (n_secmaps_found != (n_issued_SMs - n_deissued_SMs))
sewardj23eb2fd2005-04-22 16:29:19 +00004633 bad = True;
4634
4635 if (bad) {
4636 VG_(printf)("memcheck expensive sanity: "
4637 "apparent secmap leakage\n");
4638 return False;
4639 }
4640
sewardj23eb2fd2005-04-22 16:29:19 +00004641 if (bad) {
4642 VG_(printf)("memcheck expensive sanity: "
4643 "auxmap covers wrong address space\n");
4644 return False;
4645 }
4646
4647 /* there is only one pointer to each secmap (expensive) */
njn25e49d8e72002-09-23 09:36:25 +00004648
4649 return True;
4650}
sewardj45d94cc2005-04-20 14:44:11 +00004651
njn25e49d8e72002-09-23 09:36:25 +00004652/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00004653/*--- Command line args ---*/
njn25e49d8e72002-09-23 09:36:25 +00004654/*------------------------------------------------------------*/
4655
njn1d0825f2006-03-27 11:37:07 +00004656Bool MC_(clo_partial_loads_ok) = False;
sewardjfa4ca3b2007-11-30 17:19:36 +00004657Long MC_(clo_freelist_vol) = 10*1000*1000LL;
njn1d0825f2006-03-27 11:37:07 +00004658LeakCheckMode MC_(clo_leak_check) = LC_Summary;
njn5daa2d32009-07-10 08:16:29 +00004659VgRes MC_(clo_leak_resolution) = Vg_HighRes;
njn1d0825f2006-03-27 11:37:07 +00004660Bool MC_(clo_show_reachable) = False;
4661Bool MC_(clo_workaround_gcc296_bugs) = False;
sewardjeb0fa932007-11-30 21:41:40 +00004662Int MC_(clo_malloc_fill) = -1;
4663Int MC_(clo_free_fill) = -1;
sewardj7cf4e6b2008-05-01 20:24:26 +00004664Int MC_(clo_mc_level) = 2;
njn1d0825f2006-03-27 11:37:07 +00004665
4666static Bool mc_process_cmd_line_options(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00004667{
njn83df0b62009-02-25 01:01:05 +00004668 Char* tmp_str;
4669 Char* bad_level_msg =
4670 "ERROR: --track-origins=yes has no effect when --undef-value-errors=no";
4671
sewardj7cf4e6b2008-05-01 20:24:26 +00004672 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
4673
4674 /* Set MC_(clo_mc_level):
4675 1 = A bit tracking only
4676 2 = A and V bit tracking, but no V bit origins
4677 3 = A and V bit tracking, and V bit origins
4678
4679 Do this by inspecting --undef-value-errors= and
4680 --track-origins=. Reject the case --undef-value-errors=no
4681 --track-origins=yes as meaningless.
4682 */
4683 if (0 == VG_(strcmp)(arg, "--undef-value-errors=no")) {
njn83df0b62009-02-25 01:01:05 +00004684 if (MC_(clo_mc_level) == 3) {
sewardj6b523cd2009-07-15 14:49:40 +00004685 VG_(message)(Vg_DebugMsg, "%s\n", bad_level_msg);
njn83df0b62009-02-25 01:01:05 +00004686 return False;
4687 } else {
4688 MC_(clo_mc_level) = 1;
4689 return True;
4690 }
sewardj7cf4e6b2008-05-01 20:24:26 +00004691 }
4692 if (0 == VG_(strcmp)(arg, "--undef-value-errors=yes")) {
4693 if (MC_(clo_mc_level) == 1)
4694 MC_(clo_mc_level) = 2;
4695 return True;
4696 }
4697 if (0 == VG_(strcmp)(arg, "--track-origins=no")) {
4698 if (MC_(clo_mc_level) == 3)
4699 MC_(clo_mc_level) = 2;
4700 return True;
4701 }
4702 if (0 == VG_(strcmp)(arg, "--track-origins=yes")) {
njn83df0b62009-02-25 01:01:05 +00004703 if (MC_(clo_mc_level) == 1) {
sewardj6b523cd2009-07-15 14:49:40 +00004704 VG_(message)(Vg_DebugMsg, "%s\n", bad_level_msg);
njn83df0b62009-02-25 01:01:05 +00004705 return False;
4706 } else {
4707 MC_(clo_mc_level) = 3;
4708 return True;
4709 }
sewardj7cf4e6b2008-05-01 20:24:26 +00004710 }
4711
njn83df0b62009-02-25 01:01:05 +00004712 if VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok)) {}
4713 else if VG_BOOL_CLO(arg, "--show-reachable", MC_(clo_show_reachable)) {}
4714 else if VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",
4715 MC_(clo_workaround_gcc296_bugs)) {}
njn1d0825f2006-03-27 11:37:07 +00004716
njn83df0b62009-02-25 01:01:05 +00004717 else if VG_BINT_CLO(arg, "--freelist-vol", MC_(clo_freelist_vol),
4718 0, 10*1000*1000*1000LL) {}
njn1d0825f2006-03-27 11:37:07 +00004719
njn83df0b62009-02-25 01:01:05 +00004720 else if VG_XACT_CLO(arg, "--leak-check=no",
4721 MC_(clo_leak_check), LC_Off) {}
4722 else if VG_XACT_CLO(arg, "--leak-check=summary",
4723 MC_(clo_leak_check), LC_Summary) {}
4724 else if VG_XACT_CLO(arg, "--leak-check=yes",
4725 MC_(clo_leak_check), LC_Full) {}
4726 else if VG_XACT_CLO(arg, "--leak-check=full",
4727 MC_(clo_leak_check), LC_Full) {}
njn1d0825f2006-03-27 11:37:07 +00004728
njn83df0b62009-02-25 01:01:05 +00004729 else if VG_XACT_CLO(arg, "--leak-resolution=low",
4730 MC_(clo_leak_resolution), Vg_LowRes) {}
4731 else if VG_XACT_CLO(arg, "--leak-resolution=med",
4732 MC_(clo_leak_resolution), Vg_MedRes) {}
4733 else if VG_XACT_CLO(arg, "--leak-resolution=high",
4734 MC_(clo_leak_resolution), Vg_HighRes) {}
njn1d0825f2006-03-27 11:37:07 +00004735
njn83df0b62009-02-25 01:01:05 +00004736 else if VG_STR_CLO(arg, "--ignore-ranges", tmp_str) {
4737 Int i;
4738 Bool ok = parse_ignore_ranges(tmp_str);
sewardj05a46732006-10-17 01:28:10 +00004739 if (!ok)
4740 return False;
4741 tl_assert(ignoreRanges.used >= 0);
4742 tl_assert(ignoreRanges.used < M_IGNORE_RANGES);
4743 for (i = 0; i < ignoreRanges.used; i++) {
4744 Addr s = ignoreRanges.start[i];
4745 Addr e = ignoreRanges.end[i];
4746 Addr limit = 0x4000000; /* 64M - entirely arbitrary limit */
4747 if (e <= s) {
4748 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004749 "ERROR: --ignore-ranges: end <= start in range:\n");
sewardj05a46732006-10-17 01:28:10 +00004750 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004751 " 0x%lx-0x%lx\n", s, e);
sewardj05a46732006-10-17 01:28:10 +00004752 return False;
4753 }
4754 if (e - s > limit) {
4755 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004756 "ERROR: --ignore-ranges: suspiciously large range:\n");
sewardj05a46732006-10-17 01:28:10 +00004757 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004758 " 0x%lx-0x%lx (size %ld)\n", s, e, (UWord)(e-s));
sewardj05a46732006-10-17 01:28:10 +00004759 return False;
4760 }
4761 }
4762 }
4763
njn83df0b62009-02-25 01:01:05 +00004764 else if VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00,0xFF) {}
4765 else if VG_BHEX_CLO(arg, "--free-fill", MC_(clo_free_fill), 0x00,0xFF) {}
sewardjeb0fa932007-11-30 21:41:40 +00004766
njn1d0825f2006-03-27 11:37:07 +00004767 else
4768 return VG_(replacement_malloc_process_cmd_line_option)(arg);
4769
4770 return True;
njn25e49d8e72002-09-23 09:36:25 +00004771}
4772
njn51d827b2005-05-09 01:02:08 +00004773static void mc_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00004774{
njn1d0825f2006-03-27 11:37:07 +00004775 VG_(printf)(
4776" --leak-check=no|summary|full search for memory leaks at exit? [summary]\n"
njn5daa2d32009-07-10 08:16:29 +00004777" --leak-resolution=low|med|high differentiation of leak stack traces [high]\n"
njn1d0825f2006-03-27 11:37:07 +00004778" --show-reachable=no|yes show reachable blocks in leak check? [no]\n"
4779" --undef-value-errors=no|yes check for undefined value errors [yes]\n"
sewardj7cf4e6b2008-05-01 20:24:26 +00004780" --track-origins=no|yes show origins of undefined values? [no]\n"
njn1d0825f2006-03-27 11:37:07 +00004781" --partial-loads-ok=no|yes too hard to explain here; see manual [no]\n"
sewardjfa4ca3b2007-11-30 17:19:36 +00004782" --freelist-vol=<number> volume of freed blocks queue [10000000]\n"
njn1d0825f2006-03-27 11:37:07 +00004783" --workaround-gcc296-bugs=no|yes self explanatory [no]\n"
sewardj05a46732006-10-17 01:28:10 +00004784" --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS] assume given addresses are OK\n"
sewardjeb0fa932007-11-30 21:41:40 +00004785" --malloc-fill=<hexnumber> fill malloc'd areas with given value\n"
4786" --free-fill=<hexnumber> fill free'd areas with given value\n"
njn1d0825f2006-03-27 11:37:07 +00004787 );
4788 VG_(replacement_malloc_print_usage)();
njn3e884182003-04-15 13:03:23 +00004789}
4790
njn51d827b2005-05-09 01:02:08 +00004791static void mc_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00004792{
njn1d0825f2006-03-27 11:37:07 +00004793 VG_(replacement_malloc_print_debug_usage)();
njn25e49d8e72002-09-23 09:36:25 +00004794}
4795
sewardjf3418c02005-11-08 14:10:24 +00004796
nethercote8b76fe52004-11-08 19:20:09 +00004797/*------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00004798/*--- Client blocks ---*/
nethercote8b76fe52004-11-08 19:20:09 +00004799/*------------------------------------------------------------*/
4800
4801/* Client block management:
4802
4803 This is managed as an expanding array of client block descriptors.
4804 Indices of live descriptors are issued to the client, so it can ask
4805 to free them later. Therefore we cannot slide live entries down
4806 over dead ones. Instead we must use free/inuse flags and scan for
4807 an empty slot at allocation time. This in turn means allocation is
4808 relatively expensive, so we hope this does not happen too often.
nethercote8b76fe52004-11-08 19:20:09 +00004809
sewardjedc75ab2005-03-15 23:30:32 +00004810 An unused block has start == size == 0
4811*/
nethercote8b76fe52004-11-08 19:20:09 +00004812
sewardj7ce71662008-05-02 10:33:15 +00004813/* type CGenBlock is defined in mc_include.h */
nethercote8b76fe52004-11-08 19:20:09 +00004814
4815/* This subsystem is self-initialising. */
sewardj56adc352008-05-02 11:25:17 +00004816static UWord cgb_size = 0;
4817static UWord cgb_used = 0;
njn695c16e2005-03-27 03:40:28 +00004818static CGenBlock* cgbs = NULL;
nethercote8b76fe52004-11-08 19:20:09 +00004819
4820/* Stats for this subsystem. */
sewardj56adc352008-05-02 11:25:17 +00004821static ULong cgb_used_MAX = 0; /* Max in use. */
4822static ULong cgb_allocs = 0; /* Number of allocs. */
4823static ULong cgb_discards = 0; /* Number of discards. */
4824static ULong cgb_search = 0; /* Number of searches. */
nethercote8b76fe52004-11-08 19:20:09 +00004825
4826
sewardj7ce71662008-05-02 10:33:15 +00004827/* Get access to the client block array. */
4828void MC_(get_ClientBlock_array)( /*OUT*/CGenBlock** blocks,
4829 /*OUT*/UWord* nBlocks )
4830{
4831 *blocks = cgbs;
4832 *nBlocks = cgb_used;
4833}
4834
4835
nethercote8b76fe52004-11-08 19:20:09 +00004836static
njn695c16e2005-03-27 03:40:28 +00004837Int alloc_client_block ( void )
nethercote8b76fe52004-11-08 19:20:09 +00004838{
sewardj56adc352008-05-02 11:25:17 +00004839 UWord i, sz_new;
nethercote8b76fe52004-11-08 19:20:09 +00004840 CGenBlock* cgbs_new;
4841
njn695c16e2005-03-27 03:40:28 +00004842 cgb_allocs++;
nethercote8b76fe52004-11-08 19:20:09 +00004843
njn695c16e2005-03-27 03:40:28 +00004844 for (i = 0; i < cgb_used; i++) {
4845 cgb_search++;
4846 if (cgbs[i].start == 0 && cgbs[i].size == 0)
nethercote8b76fe52004-11-08 19:20:09 +00004847 return i;
4848 }
4849
4850 /* Not found. Try to allocate one at the end. */
njn695c16e2005-03-27 03:40:28 +00004851 if (cgb_used < cgb_size) {
4852 cgb_used++;
4853 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004854 }
4855
4856 /* Ok, we have to allocate a new one. */
njn695c16e2005-03-27 03:40:28 +00004857 tl_assert(cgb_used == cgb_size);
4858 sz_new = (cgbs == NULL) ? 10 : (2 * cgb_size);
nethercote8b76fe52004-11-08 19:20:09 +00004859
sewardj9c606bd2008-09-18 18:12:50 +00004860 cgbs_new = VG_(malloc)( "mc.acb.1", sz_new * sizeof(CGenBlock) );
njn695c16e2005-03-27 03:40:28 +00004861 for (i = 0; i < cgb_used; i++)
4862 cgbs_new[i] = cgbs[i];
nethercote8b76fe52004-11-08 19:20:09 +00004863
njn695c16e2005-03-27 03:40:28 +00004864 if (cgbs != NULL)
4865 VG_(free)( cgbs );
4866 cgbs = cgbs_new;
nethercote8b76fe52004-11-08 19:20:09 +00004867
njn695c16e2005-03-27 03:40:28 +00004868 cgb_size = sz_new;
4869 cgb_used++;
4870 if (cgb_used > cgb_used_MAX)
4871 cgb_used_MAX = cgb_used;
4872 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004873}
4874
4875
4876static void show_client_block_stats ( void )
4877{
4878 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004879 "general CBs: %llu allocs, %llu discards, %llu maxinuse, %llu search\n",
njn695c16e2005-03-27 03:40:28 +00004880 cgb_allocs, cgb_discards, cgb_used_MAX, cgb_search
nethercote8b76fe52004-11-08 19:20:09 +00004881 );
4882}
4883
nethercote8b76fe52004-11-08 19:20:09 +00004884
sewardj7ce71662008-05-02 10:33:15 +00004885/*------------------------------------------------------------*/
4886/*--- Client requests ---*/
4887/*------------------------------------------------------------*/
nethercote8b76fe52004-11-08 19:20:09 +00004888
njn51d827b2005-05-09 01:02:08 +00004889static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
nethercote8b76fe52004-11-08 19:20:09 +00004890{
4891 Int i;
4892 Bool ok;
4893 Addr bad_addr;
4894
njnfc26ff92004-11-22 19:12:49 +00004895 if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
sewardj7ce71662008-05-02 10:33:15 +00004896 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
4897 && VG_USERREQ__FREELIKE_BLOCK != arg[0]
4898 && VG_USERREQ__CREATE_MEMPOOL != arg[0]
4899 && VG_USERREQ__DESTROY_MEMPOOL != arg[0]
4900 && VG_USERREQ__MEMPOOL_ALLOC != arg[0]
4901 && VG_USERREQ__MEMPOOL_FREE != arg[0]
4902 && VG_USERREQ__MEMPOOL_TRIM != arg[0]
4903 && VG_USERREQ__MOVE_MEMPOOL != arg[0]
4904 && VG_USERREQ__MEMPOOL_CHANGE != arg[0]
4905 && VG_USERREQ__MEMPOOL_EXISTS != arg[0])
nethercote8b76fe52004-11-08 19:20:09 +00004906 return False;
4907
4908 switch (arg[0]) {
njndbf7ca72006-03-31 11:57:59 +00004909 case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE:
4910 ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
nethercote8b76fe52004-11-08 19:20:09 +00004911 if (!ok)
sewardj7ce71662008-05-02 10:33:15 +00004912 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004913 *ret = ok ? (UWord)NULL : bad_addr;
sewardj8cf88b72005-07-08 01:29:33 +00004914 break;
nethercote8b76fe52004-11-08 19:20:09 +00004915
njndbf7ca72006-03-31 11:57:59 +00004916 case VG_USERREQ__CHECK_MEM_IS_DEFINED: {
nethercote8b76fe52004-11-08 19:20:09 +00004917 MC_ReadResult res;
sewardj7cf4e6b2008-05-01 20:24:26 +00004918 UInt otag = 0;
4919 res = is_mem_defined ( arg[1], arg[2], &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00004920 if (MC_AddrErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004921 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004922 else if (MC_ValueErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004923 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/False, otag );
nethercote8b76fe52004-11-08 19:20:09 +00004924 *ret = ( res==MC_Ok ? (UWord)NULL : bad_addr );
sewardj8cf88b72005-07-08 01:29:33 +00004925 break;
nethercote8b76fe52004-11-08 19:20:09 +00004926 }
4927
4928 case VG_USERREQ__DO_LEAK_CHECK:
njn8225cc02009-03-09 22:52:24 +00004929 MC_(detect_memory_leaks)(tid, arg[1] ? LC_Summary : LC_Full);
sewardj8cf88b72005-07-08 01:29:33 +00004930 *ret = 0; /* return value is meaningless */
4931 break;
nethercote8b76fe52004-11-08 19:20:09 +00004932
njndbf7ca72006-03-31 11:57:59 +00004933 case VG_USERREQ__MAKE_MEM_NOACCESS:
4934 MC_(make_mem_noaccess) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004935 *ret = -1;
4936 break;
nethercote8b76fe52004-11-08 19:20:09 +00004937
njndbf7ca72006-03-31 11:57:59 +00004938 case VG_USERREQ__MAKE_MEM_UNDEFINED:
sewardj7ce71662008-05-02 10:33:15 +00004939 make_mem_undefined_w_tid_and_okind ( arg[1], arg[2], tid,
4940 MC_OKIND_USER );
sewardjedc75ab2005-03-15 23:30:32 +00004941 *ret = -1;
sewardj8cf88b72005-07-08 01:29:33 +00004942 break;
nethercote8b76fe52004-11-08 19:20:09 +00004943
njndbf7ca72006-03-31 11:57:59 +00004944 case VG_USERREQ__MAKE_MEM_DEFINED:
4945 MC_(make_mem_defined) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004946 *ret = -1;
nethercote8b76fe52004-11-08 19:20:09 +00004947 break;
4948
njndbf7ca72006-03-31 11:57:59 +00004949 case VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE:
4950 make_mem_defined_if_addressable ( arg[1], arg[2] );
sewardjfb1e9ad2006-03-10 13:41:58 +00004951 *ret = -1;
4952 break;
4953
sewardjedc75ab2005-03-15 23:30:32 +00004954 case VG_USERREQ__CREATE_BLOCK: /* describe a block */
sewardj8cf88b72005-07-08 01:29:33 +00004955 if (arg[1] != 0 && arg[2] != 0) {
4956 i = alloc_client_block();
4957 /* VG_(printf)("allocated %d %p\n", i, cgbs); */
4958 cgbs[i].start = arg[1];
4959 cgbs[i].size = arg[2];
sewardj9c606bd2008-09-18 18:12:50 +00004960 cgbs[i].desc = VG_(strdup)("mc.mhcr.1", (Char *)arg[3]);
sewardj39f34232007-11-09 23:02:28 +00004961 cgbs[i].where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
sewardj8cf88b72005-07-08 01:29:33 +00004962 *ret = i;
4963 } else
4964 *ret = -1;
4965 break;
sewardjedc75ab2005-03-15 23:30:32 +00004966
nethercote8b76fe52004-11-08 19:20:09 +00004967 case VG_USERREQ__DISCARD: /* discard */
njn695c16e2005-03-27 03:40:28 +00004968 if (cgbs == NULL
4969 || arg[2] >= cgb_used ||
sewardj8cf88b72005-07-08 01:29:33 +00004970 (cgbs[arg[2]].start == 0 && cgbs[arg[2]].size == 0)) {
sewardjedc75ab2005-03-15 23:30:32 +00004971 *ret = 1;
sewardj8cf88b72005-07-08 01:29:33 +00004972 } else {
4973 tl_assert(arg[2] >= 0 && arg[2] < cgb_used);
4974 cgbs[arg[2]].start = cgbs[arg[2]].size = 0;
4975 VG_(free)(cgbs[arg[2]].desc);
4976 cgb_discards++;
4977 *ret = 0;
4978 }
4979 break;
nethercote8b76fe52004-11-08 19:20:09 +00004980
sewardjc2c12c22006-03-08 13:20:09 +00004981 case VG_USERREQ__GET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004982 *ret = mc_get_or_set_vbits_for_client
njn1dcee092009-02-24 03:07:37 +00004983 ( arg[1], arg[2], arg[3], False /* get them */ );
sewardjc2c12c22006-03-08 13:20:09 +00004984 break;
4985
4986 case VG_USERREQ__SET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004987 *ret = mc_get_or_set_vbits_for_client
njn1dcee092009-02-24 03:07:37 +00004988 ( arg[1], arg[2], arg[3], True /* set them */ );
sewardjc2c12c22006-03-08 13:20:09 +00004989 break;
nethercote8b76fe52004-11-08 19:20:09 +00004990
njn1d0825f2006-03-27 11:37:07 +00004991 case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
4992 UWord** argp = (UWord**)arg;
4993 // MC_(bytes_leaked) et al were set by the last leak check (or zero
4994 // if no prior leak checks performed).
4995 *argp[1] = MC_(bytes_leaked) + MC_(bytes_indirect);
4996 *argp[2] = MC_(bytes_dubious);
4997 *argp[3] = MC_(bytes_reachable);
4998 *argp[4] = MC_(bytes_suppressed);
4999 // there is no argp[5]
5000 //*argp[5] = MC_(bytes_indirect);
njn8df80b22009-03-02 05:11:06 +00005001 // XXX need to make *argp[1-4] defined; currently done in the
5002 // VALGRIND_COUNT_LEAKS_MACRO by initialising them to zero.
5003 *ret = 0;
5004 return True;
5005 }
5006 case VG_USERREQ__COUNT_LEAK_BLOCKS: { /* count leaked blocks */
5007 UWord** argp = (UWord**)arg;
5008 // MC_(blocks_leaked) et al were set by the last leak check (or zero
5009 // if no prior leak checks performed).
5010 *argp[1] = MC_(blocks_leaked) + MC_(blocks_indirect);
5011 *argp[2] = MC_(blocks_dubious);
5012 *argp[3] = MC_(blocks_reachable);
5013 *argp[4] = MC_(blocks_suppressed);
5014 // there is no argp[5]
5015 //*argp[5] = MC_(blocks_indirect);
5016 // XXX need to make *argp[1-4] defined; currently done in the
5017 // VALGRIND_COUNT_LEAK_BLOCKS_MACRO by initialising them to zero.
njn1d0825f2006-03-27 11:37:07 +00005018 *ret = 0;
5019 return True;
5020 }
5021 case VG_USERREQ__MALLOCLIKE_BLOCK: {
5022 Addr p = (Addr)arg[1];
5023 SizeT sizeB = arg[2];
njn1dcee092009-02-24 03:07:37 +00005024 //UInt rzB = arg[3]; XXX: unused!
njn1d0825f2006-03-27 11:37:07 +00005025 Bool is_zeroed = (Bool)arg[4];
5026
njn1dcee092009-02-24 03:07:37 +00005027 MC_(new_block) ( tid, p, sizeB, /*ignored*/0, is_zeroed,
njn1d0825f2006-03-27 11:37:07 +00005028 MC_AllocCustom, MC_(malloc_list) );
5029 return True;
5030 }
5031 case VG_USERREQ__FREELIKE_BLOCK: {
5032 Addr p = (Addr)arg[1];
5033 UInt rzB = arg[2];
5034
5035 MC_(handle_free) ( tid, p, rzB, MC_AllocCustom );
5036 return True;
5037 }
5038
5039 case _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR: {
njn718d3b12006-12-16 00:54:12 +00005040 Char* s = (Char*)arg[1];
5041 Addr dst = (Addr) arg[2];
5042 Addr src = (Addr) arg[3];
5043 SizeT len = (SizeT)arg[4];
sewardj7ce71662008-05-02 10:33:15 +00005044 MC_(record_overlap_error)(tid, s, src, dst, len);
njn1d0825f2006-03-27 11:37:07 +00005045 return True;
5046 }
5047
5048 case VG_USERREQ__CREATE_MEMPOOL: {
5049 Addr pool = (Addr)arg[1];
5050 UInt rzB = arg[2];
5051 Bool is_zeroed = (Bool)arg[3];
5052
5053 MC_(create_mempool) ( pool, rzB, is_zeroed );
5054 return True;
5055 }
5056
5057 case VG_USERREQ__DESTROY_MEMPOOL: {
5058 Addr pool = (Addr)arg[1];
5059
5060 MC_(destroy_mempool) ( pool );
5061 return True;
5062 }
5063
5064 case VG_USERREQ__MEMPOOL_ALLOC: {
5065 Addr pool = (Addr)arg[1];
5066 Addr addr = (Addr)arg[2];
5067 UInt size = arg[3];
5068
5069 MC_(mempool_alloc) ( tid, pool, addr, size );
5070 return True;
5071 }
5072
5073 case VG_USERREQ__MEMPOOL_FREE: {
5074 Addr pool = (Addr)arg[1];
5075 Addr addr = (Addr)arg[2];
5076
5077 MC_(mempool_free) ( pool, addr );
5078 return True;
5079 }
5080
sewardj2c1c9df2006-07-28 00:06:37 +00005081 case VG_USERREQ__MEMPOOL_TRIM: {
5082 Addr pool = (Addr)arg[1];
5083 Addr addr = (Addr)arg[2];
5084 UInt size = arg[3];
5085
5086 MC_(mempool_trim) ( pool, addr, size );
5087 return True;
5088 }
5089
sewardjc740d762006-10-05 17:59:23 +00005090 case VG_USERREQ__MOVE_MEMPOOL: {
5091 Addr poolA = (Addr)arg[1];
5092 Addr poolB = (Addr)arg[2];
5093
5094 MC_(move_mempool) ( poolA, poolB );
5095 return True;
5096 }
5097
5098 case VG_USERREQ__MEMPOOL_CHANGE: {
5099 Addr pool = (Addr)arg[1];
5100 Addr addrA = (Addr)arg[2];
5101 Addr addrB = (Addr)arg[3];
5102 UInt size = arg[4];
5103
5104 MC_(mempool_change) ( pool, addrA, addrB, size );
5105 return True;
5106 }
5107
5108 case VG_USERREQ__MEMPOOL_EXISTS: {
5109 Addr pool = (Addr)arg[1];
5110
5111 *ret = (UWord) MC_(mempool_exists) ( pool );
5112 return True;
5113 }
5114
5115
nethercote8b76fe52004-11-08 19:20:09 +00005116 default:
sewardj6b523cd2009-07-15 14:49:40 +00005117 VG_(message)(
5118 Vg_UserMsg,
5119 "Warning: unknown memcheck client request code %llx\n",
5120 (ULong)arg[0]
5121 );
njn1d0825f2006-03-27 11:37:07 +00005122 return False;
nethercote8b76fe52004-11-08 19:20:09 +00005123 }
5124 return True;
5125}
njn25e49d8e72002-09-23 09:36:25 +00005126
njnf76d27a2009-05-28 01:53:07 +00005127
njn25e49d8e72002-09-23 09:36:25 +00005128/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +00005129/*--- Crude profiling machinery. ---*/
5130/*------------------------------------------------------------*/
5131
5132// We track a number of interesting events (using PROF_EVENT)
5133// if MC_PROFILE_MEMORY is defined.
5134
5135#ifdef MC_PROFILE_MEMORY
5136
5137UInt MC_(event_ctr)[N_PROF_EVENTS];
5138HChar* MC_(event_ctr_name)[N_PROF_EVENTS];
5139
5140static void init_prof_mem ( void )
5141{
5142 Int i;
5143 for (i = 0; i < N_PROF_EVENTS; i++) {
5144 MC_(event_ctr)[i] = 0;
5145 MC_(event_ctr_name)[i] = NULL;
5146 }
5147}
5148
5149static void done_prof_mem ( void )
5150{
5151 Int i;
5152 Bool spaced = False;
5153 for (i = 0; i < N_PROF_EVENTS; i++) {
5154 if (!spaced && (i % 10) == 0) {
5155 VG_(printf)("\n");
5156 spaced = True;
5157 }
5158 if (MC_(event_ctr)[i] > 0) {
5159 spaced = False;
5160 VG_(printf)( "prof mem event %3d: %9d %s\n",
5161 i, MC_(event_ctr)[i],
5162 MC_(event_ctr_name)[i]
5163 ? MC_(event_ctr_name)[i] : "unnamed");
5164 }
5165 }
5166}
5167
5168#else
5169
5170static void init_prof_mem ( void ) { }
5171static void done_prof_mem ( void ) { }
5172
5173#endif
5174
sewardj7cf4e6b2008-05-01 20:24:26 +00005175
5176/*------------------------------------------------------------*/
5177/*--- Origin tracking stuff ---*/
5178/*------------------------------------------------------------*/
5179
5180/*--------------------------------------------*/
5181/*--- Origin tracking: load handlers ---*/
5182/*--------------------------------------------*/
5183
5184static INLINE UInt merge_origins ( UInt or1, UInt or2 ) {
5185 return or1 > or2 ? or1 : or2;
5186}
5187
5188UWord VG_REGPARM(1) MC_(helperc_b_load1)( Addr a ) {
5189 OCacheLine* line;
5190 UChar descr;
5191 UWord lineoff = oc_line_offset(a);
5192 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5193
5194 if (OC_ENABLE_ASSERTIONS) {
5195 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5196 }
5197
5198 line = find_OCacheLine( a );
5199
5200 descr = line->descr[lineoff];
5201 if (OC_ENABLE_ASSERTIONS) {
5202 tl_assert(descr < 0x10);
5203 }
5204
5205 if (LIKELY(0 == (descr & (1 << byteoff)))) {
5206 return 0;
5207 } else {
5208 return line->w32[lineoff];
5209 }
5210}
5211
5212UWord VG_REGPARM(1) MC_(helperc_b_load2)( Addr a ) {
5213 OCacheLine* line;
5214 UChar descr;
5215 UWord lineoff, byteoff;
5216
5217 if (UNLIKELY(a & 1)) {
5218 /* Handle misaligned case, slowly. */
5219 UInt oLo = (UInt)MC_(helperc_b_load1)( a + 0 );
5220 UInt oHi = (UInt)MC_(helperc_b_load1)( a + 1 );
5221 return merge_origins(oLo, oHi);
5222 }
5223
5224 lineoff = oc_line_offset(a);
5225 byteoff = a & 3; /* 0 or 2 */
5226
5227 if (OC_ENABLE_ASSERTIONS) {
5228 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5229 }
5230 line = find_OCacheLine( a );
5231
5232 descr = line->descr[lineoff];
5233 if (OC_ENABLE_ASSERTIONS) {
5234 tl_assert(descr < 0x10);
5235 }
5236
5237 if (LIKELY(0 == (descr & (3 << byteoff)))) {
5238 return 0;
5239 } else {
5240 return line->w32[lineoff];
5241 }
5242}
5243
5244UWord VG_REGPARM(1) MC_(helperc_b_load4)( Addr a ) {
5245 OCacheLine* line;
5246 UChar descr;
5247 UWord lineoff;
5248
5249 if (UNLIKELY(a & 3)) {
5250 /* Handle misaligned case, slowly. */
5251 UInt oLo = (UInt)MC_(helperc_b_load2)( a + 0 );
5252 UInt oHi = (UInt)MC_(helperc_b_load2)( a + 2 );
5253 return merge_origins(oLo, oHi);
5254 }
5255
5256 lineoff = oc_line_offset(a);
5257 if (OC_ENABLE_ASSERTIONS) {
5258 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5259 }
5260
5261 line = find_OCacheLine( a );
5262
5263 descr = line->descr[lineoff];
5264 if (OC_ENABLE_ASSERTIONS) {
5265 tl_assert(descr < 0x10);
5266 }
5267
5268 if (LIKELY(0 == descr)) {
5269 return 0;
5270 } else {
5271 return line->w32[lineoff];
5272 }
5273}
5274
5275UWord VG_REGPARM(1) MC_(helperc_b_load8)( Addr a ) {
5276 OCacheLine* line;
5277 UChar descrLo, descrHi, descr;
5278 UWord lineoff;
5279
5280 if (UNLIKELY(a & 7)) {
5281 /* Handle misaligned case, slowly. */
5282 UInt oLo = (UInt)MC_(helperc_b_load4)( a + 0 );
5283 UInt oHi = (UInt)MC_(helperc_b_load4)( a + 4 );
5284 return merge_origins(oLo, oHi);
5285 }
5286
5287 lineoff = oc_line_offset(a);
5288 if (OC_ENABLE_ASSERTIONS) {
5289 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5290 }
5291
5292 line = find_OCacheLine( a );
5293
5294 descrLo = line->descr[lineoff + 0];
5295 descrHi = line->descr[lineoff + 1];
5296 descr = descrLo | descrHi;
5297 if (OC_ENABLE_ASSERTIONS) {
5298 tl_assert(descr < 0x10);
5299 }
5300
5301 if (LIKELY(0 == descr)) {
5302 return 0; /* both 32-bit chunks are defined */
5303 } else {
5304 UInt oLo = descrLo == 0 ? 0 : line->w32[lineoff + 0];
5305 UInt oHi = descrHi == 0 ? 0 : line->w32[lineoff + 1];
5306 return merge_origins(oLo, oHi);
5307 }
5308}
5309
5310UWord VG_REGPARM(1) MC_(helperc_b_load16)( Addr a ) {
5311 UInt oLo = (UInt)MC_(helperc_b_load8)( a + 0 );
5312 UInt oHi = (UInt)MC_(helperc_b_load8)( a + 8 );
5313 UInt oBoth = merge_origins(oLo, oHi);
5314 return (UWord)oBoth;
5315}
5316
5317
5318/*--------------------------------------------*/
5319/*--- Origin tracking: store handlers ---*/
5320/*--------------------------------------------*/
5321
5322void VG_REGPARM(2) MC_(helperc_b_store1)( Addr a, UWord d32 ) {
5323 OCacheLine* line;
5324 UWord lineoff = oc_line_offset(a);
5325 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5326
5327 if (OC_ENABLE_ASSERTIONS) {
5328 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5329 }
5330
5331 line = find_OCacheLine( a );
5332
5333 if (d32 == 0) {
5334 line->descr[lineoff] &= ~(1 << byteoff);
5335 } else {
5336 line->descr[lineoff] |= (1 << byteoff);
5337 line->w32[lineoff] = d32;
5338 }
5339}
5340
5341void VG_REGPARM(2) MC_(helperc_b_store2)( Addr a, UWord d32 ) {
5342 OCacheLine* line;
5343 UWord lineoff, byteoff;
5344
5345 if (UNLIKELY(a & 1)) {
5346 /* Handle misaligned case, slowly. */
5347 MC_(helperc_b_store1)( a + 0, d32 );
5348 MC_(helperc_b_store1)( a + 1, d32 );
5349 return;
5350 }
5351
5352 lineoff = oc_line_offset(a);
5353 byteoff = a & 3; /* 0 or 2 */
5354
5355 if (OC_ENABLE_ASSERTIONS) {
5356 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5357 }
5358
5359 line = find_OCacheLine( a );
5360
5361 if (d32 == 0) {
5362 line->descr[lineoff] &= ~(3 << byteoff);
5363 } else {
5364 line->descr[lineoff] |= (3 << byteoff);
5365 line->w32[lineoff] = d32;
5366 }
5367}
5368
5369void VG_REGPARM(2) MC_(helperc_b_store4)( Addr a, UWord d32 ) {
5370 OCacheLine* line;
5371 UWord lineoff;
5372
5373 if (UNLIKELY(a & 3)) {
5374 /* Handle misaligned case, slowly. */
5375 MC_(helperc_b_store2)( a + 0, d32 );
5376 MC_(helperc_b_store2)( a + 2, d32 );
5377 return;
5378 }
5379
5380 lineoff = oc_line_offset(a);
5381 if (OC_ENABLE_ASSERTIONS) {
5382 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5383 }
5384
5385 line = find_OCacheLine( a );
5386
5387 if (d32 == 0) {
5388 line->descr[lineoff] = 0;
5389 } else {
5390 line->descr[lineoff] = 0xF;
5391 line->w32[lineoff] = d32;
5392 }
5393}
5394
5395void VG_REGPARM(2) MC_(helperc_b_store8)( Addr a, UWord d32 ) {
5396 OCacheLine* line;
5397 UWord lineoff;
5398
5399 if (UNLIKELY(a & 7)) {
5400 /* Handle misaligned case, slowly. */
5401 MC_(helperc_b_store4)( a + 0, d32 );
5402 MC_(helperc_b_store4)( a + 4, d32 );
5403 return;
5404 }
5405
5406 lineoff = oc_line_offset(a);
5407 if (OC_ENABLE_ASSERTIONS) {
5408 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5409 }
5410
5411 line = find_OCacheLine( a );
5412
5413 if (d32 == 0) {
5414 line->descr[lineoff + 0] = 0;
5415 line->descr[lineoff + 1] = 0;
5416 } else {
5417 line->descr[lineoff + 0] = 0xF;
5418 line->descr[lineoff + 1] = 0xF;
5419 line->w32[lineoff + 0] = d32;
5420 line->w32[lineoff + 1] = d32;
5421 }
5422}
5423
5424void VG_REGPARM(2) MC_(helperc_b_store16)( Addr a, UWord d32 ) {
5425 MC_(helperc_b_store8)( a + 0, d32 );
5426 MC_(helperc_b_store8)( a + 8, d32 );
5427}
5428
5429
5430/*--------------------------------------------*/
5431/*--- Origin tracking: sarp handlers ---*/
5432/*--------------------------------------------*/
5433
5434__attribute__((noinline))
5435static void ocache_sarp_Set_Origins ( Addr a, UWord len, UInt otag ) {
5436 if ((a & 1) && len >= 1) {
5437 MC_(helperc_b_store1)( a, otag );
5438 a++;
5439 len--;
5440 }
5441 if ((a & 2) && len >= 2) {
5442 MC_(helperc_b_store2)( a, otag );
5443 a += 2;
5444 len -= 2;
5445 }
5446 if (len >= 4)
5447 tl_assert(0 == (a & 3));
5448 while (len >= 4) {
5449 MC_(helperc_b_store4)( a, otag );
5450 a += 4;
5451 len -= 4;
5452 }
5453 if (len >= 2) {
5454 MC_(helperc_b_store2)( a, otag );
5455 a += 2;
5456 len -= 2;
5457 }
5458 if (len >= 1) {
5459 MC_(helperc_b_store1)( a, otag );
njn4c245e52009-03-15 23:25:38 +00005460 //a++;
sewardj7cf4e6b2008-05-01 20:24:26 +00005461 len--;
5462 }
5463 tl_assert(len == 0);
5464}
5465
5466__attribute__((noinline))
5467static void ocache_sarp_Clear_Origins ( Addr a, UWord len ) {
5468 if ((a & 1) && len >= 1) {
5469 MC_(helperc_b_store1)( a, 0 );
5470 a++;
5471 len--;
5472 }
5473 if ((a & 2) && len >= 2) {
5474 MC_(helperc_b_store2)( a, 0 );
5475 a += 2;
5476 len -= 2;
5477 }
5478 if (len >= 4)
5479 tl_assert(0 == (a & 3));
5480 while (len >= 4) {
5481 MC_(helperc_b_store4)( a, 0 );
5482 a += 4;
5483 len -= 4;
5484 }
5485 if (len >= 2) {
5486 MC_(helperc_b_store2)( a, 0 );
5487 a += 2;
5488 len -= 2;
5489 }
5490 if (len >= 1) {
5491 MC_(helperc_b_store1)( a, 0 );
njn4c245e52009-03-15 23:25:38 +00005492 //a++;
sewardj7cf4e6b2008-05-01 20:24:26 +00005493 len--;
5494 }
5495 tl_assert(len == 0);
5496}
5497
5498
njn1d0825f2006-03-27 11:37:07 +00005499/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00005500/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00005501/*------------------------------------------------------------*/
5502
njn51d827b2005-05-09 01:02:08 +00005503static void mc_post_clo_init ( void )
njn5c004e42002-11-18 11:04:50 +00005504{
sewardj71bc3cb2005-05-19 00:25:45 +00005505 /* If we've been asked to emit XML, mash around various other
5506 options so as to constrain the output somewhat. */
5507 if (VG_(clo_xml)) {
5508 /* Extract as much info as possible from the leak checker. */
njn1d0825f2006-03-27 11:37:07 +00005509 /* MC_(clo_show_reachable) = True; */
5510 MC_(clo_leak_check) = LC_Full;
sewardj71bc3cb2005-05-19 00:25:45 +00005511 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005512
5513 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
5514
5515 if (MC_(clo_mc_level) == 3) {
5516 /* We're doing origin tracking. */
5517# ifdef PERF_FAST_STACK
5518 VG_(track_new_mem_stack_4_w_ECU) ( mc_new_mem_stack_4_w_ECU );
5519 VG_(track_new_mem_stack_8_w_ECU) ( mc_new_mem_stack_8_w_ECU );
5520 VG_(track_new_mem_stack_12_w_ECU) ( mc_new_mem_stack_12_w_ECU );
5521 VG_(track_new_mem_stack_16_w_ECU) ( mc_new_mem_stack_16_w_ECU );
5522 VG_(track_new_mem_stack_32_w_ECU) ( mc_new_mem_stack_32_w_ECU );
5523 VG_(track_new_mem_stack_112_w_ECU) ( mc_new_mem_stack_112_w_ECU );
5524 VG_(track_new_mem_stack_128_w_ECU) ( mc_new_mem_stack_128_w_ECU );
5525 VG_(track_new_mem_stack_144_w_ECU) ( mc_new_mem_stack_144_w_ECU );
5526 VG_(track_new_mem_stack_160_w_ECU) ( mc_new_mem_stack_160_w_ECU );
5527# endif
5528 VG_(track_new_mem_stack_w_ECU) ( mc_new_mem_stack_w_ECU );
5529 } else {
5530 /* Not doing origin tracking */
5531# ifdef PERF_FAST_STACK
5532 VG_(track_new_mem_stack_4) ( mc_new_mem_stack_4 );
5533 VG_(track_new_mem_stack_8) ( mc_new_mem_stack_8 );
5534 VG_(track_new_mem_stack_12) ( mc_new_mem_stack_12 );
5535 VG_(track_new_mem_stack_16) ( mc_new_mem_stack_16 );
5536 VG_(track_new_mem_stack_32) ( mc_new_mem_stack_32 );
5537 VG_(track_new_mem_stack_112) ( mc_new_mem_stack_112 );
5538 VG_(track_new_mem_stack_128) ( mc_new_mem_stack_128 );
5539 VG_(track_new_mem_stack_144) ( mc_new_mem_stack_144 );
5540 VG_(track_new_mem_stack_160) ( mc_new_mem_stack_160 );
5541# endif
5542 VG_(track_new_mem_stack) ( mc_new_mem_stack );
5543 }
sewardj9d624d12008-05-02 13:35:29 +00005544
5545 /* This origin tracking cache is huge (~100M), so only initialise
5546 if we need it. */
5547 if (MC_(clo_mc_level) >= 3) {
5548 init_OCache();
sewardj77139802008-05-05 09:48:56 +00005549 tl_assert(ocacheL1 != NULL);
sewardj9d624d12008-05-02 13:35:29 +00005550 tl_assert(ocacheL2 != NULL);
5551 } else {
sewardj77139802008-05-05 09:48:56 +00005552 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005553 tl_assert(ocacheL2 == NULL);
5554 }
njn5c004e42002-11-18 11:04:50 +00005555}
5556
njn1d0825f2006-03-27 11:37:07 +00005557static void print_SM_info(char* type, int n_SMs)
5558{
5559 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005560 " memcheck: SMs: %s = %d (%ldk, %ldM)\n",
njn1d0825f2006-03-27 11:37:07 +00005561 type,
5562 n_SMs,
barta0b6b2c2008-07-07 06:49:24 +00005563 n_SMs * sizeof(SecMap) / 1024UL,
5564 n_SMs * sizeof(SecMap) / (1024 * 1024UL) );
njn1d0825f2006-03-27 11:37:07 +00005565}
5566
njn51d827b2005-05-09 01:02:08 +00005567static void mc_fini ( Int exitcode )
njn5c004e42002-11-18 11:04:50 +00005568{
njn1d0825f2006-03-27 11:37:07 +00005569 MC_(print_malloc_stats)();
sewardj23eb2fd2005-04-22 16:29:19 +00005570
njn1d0825f2006-03-27 11:37:07 +00005571 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5572 if (MC_(clo_leak_check) == LC_Off)
5573 VG_(message)(Vg_UserMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005574 "For a detailed leak analysis, rerun with: --leak-check=yes\n");
njn1d0825f2006-03-27 11:37:07 +00005575
5576 VG_(message)(Vg_UserMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005577 "For counts of detected errors, rerun with: -v\n");
njn1d0825f2006-03-27 11:37:07 +00005578 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005579
5580
sewardj7ce71662008-05-02 10:33:15 +00005581 if (MC_(any_value_errors) && !VG_(clo_xml) && VG_(clo_verbosity) >= 1
sewardj7cf4e6b2008-05-01 20:24:26 +00005582 && MC_(clo_mc_level) == 2) {
5583 VG_(message)(Vg_UserMsg,
5584 "Use --track-origins=yes to see where "
sewardj6b523cd2009-07-15 14:49:40 +00005585 "uninitialised values come from\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00005586 }
5587
njn1d0825f2006-03-27 11:37:07 +00005588 if (MC_(clo_leak_check) != LC_Off)
njn8225cc02009-03-09 22:52:24 +00005589 MC_(detect_memory_leaks)(1/*bogus ThreadId*/, MC_(clo_leak_check));
njn1d0825f2006-03-27 11:37:07 +00005590
5591 done_prof_mem();
sewardjae986ca2005-10-12 12:53:20 +00005592
sewardj45d94cc2005-04-20 14:44:11 +00005593 if (VG_(clo_verbosity) > 1) {
njn1d0825f2006-03-27 11:37:07 +00005594 SizeT max_secVBit_szB, max_SMs_szB, max_shmem_szB;
5595
sewardj45d94cc2005-04-20 14:44:11 +00005596 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005597 " memcheck: sanity checks: %d cheap, %d expensive\n",
sewardj23eb2fd2005-04-22 16:29:19 +00005598 n_sanity_cheap, n_sanity_expensive );
sewardj45d94cc2005-04-20 14:44:11 +00005599 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005600 " memcheck: auxmaps: %lld auxmap entries (%lldk, %lldM) in use\n",
sewardj05a46732006-10-17 01:28:10 +00005601 n_auxmap_L2_nodes,
5602 n_auxmap_L2_nodes * 64,
5603 n_auxmap_L2_nodes / 16 );
sewardj23eb2fd2005-04-22 16:29:19 +00005604 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005605 " memcheck: auxmaps_L1: %lld searches, %lld cmps, ratio %lld:10\n",
sewardj05a46732006-10-17 01:28:10 +00005606 n_auxmap_L1_searches, n_auxmap_L1_cmps,
5607 (10ULL * n_auxmap_L1_cmps)
5608 / (n_auxmap_L1_searches ? n_auxmap_L1_searches : 1)
5609 );
5610 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005611 " memcheck: auxmaps_L2: %lld searches, %lld nodes\n",
sewardj05a46732006-10-17 01:28:10 +00005612 n_auxmap_L2_searches, n_auxmap_L2_nodes
5613 );
sewardj23eb2fd2005-04-22 16:29:19 +00005614
njndbf7ca72006-03-31 11:57:59 +00005615 print_SM_info("n_issued ", n_issued_SMs);
5616 print_SM_info("n_deissued ", n_deissued_SMs);
5617 print_SM_info("max_noaccess ", max_noaccess_SMs);
5618 print_SM_info("max_undefined", max_undefined_SMs);
5619 print_SM_info("max_defined ", max_defined_SMs);
5620 print_SM_info("max_non_DSM ", max_non_DSM_SMs);
njn1d0825f2006-03-27 11:37:07 +00005621
5622 // Three DSMs, plus the non-DSM ones
5623 max_SMs_szB = (3 + max_non_DSM_SMs) * sizeof(SecMap);
5624 // The 3*sizeof(Word) bytes is the AVL node metadata size.
5625 // The 4*sizeof(Word) bytes is the malloc metadata size.
5626 // Hardwiring these sizes in sucks, but I don't see how else to do it.
5627 max_secVBit_szB = max_secVBit_nodes *
5628 (sizeof(SecVBitNode) + 3*sizeof(Word) + 4*sizeof(Word));
5629 max_shmem_szB = sizeof(primary_map) + max_SMs_szB + max_secVBit_szB;
sewardj23eb2fd2005-04-22 16:29:19 +00005630
5631 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005632 " memcheck: max sec V bit nodes: %d (%ldk, %ldM)\n",
njn1d0825f2006-03-27 11:37:07 +00005633 max_secVBit_nodes, max_secVBit_szB / 1024,
5634 max_secVBit_szB / (1024 * 1024));
5635 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005636 " memcheck: set_sec_vbits8 calls: %llu (new: %llu, updates: %llu)\n",
njn1d0825f2006-03-27 11:37:07 +00005637 sec_vbits_new_nodes + sec_vbits_updates,
5638 sec_vbits_new_nodes, sec_vbits_updates );
5639 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005640 " memcheck: max shadow mem size: %ldk, %ldM\n",
njn1d0825f2006-03-27 11:37:07 +00005641 max_shmem_szB / 1024, max_shmem_szB / (1024 * 1024));
sewardj7cf4e6b2008-05-01 20:24:26 +00005642
5643 if (MC_(clo_mc_level) >= 3) {
5644 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005645 " ocacheL1: %'12lu refs %'12lu misses (%'lu lossage)\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005646 stats_ocacheL1_find,
5647 stats_ocacheL1_misses,
5648 stats_ocacheL1_lossage );
5649 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005650 " ocacheL1: %'12lu at 0 %'12lu at 1\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005651 stats_ocacheL1_find - stats_ocacheL1_misses
5652 - stats_ocacheL1_found_at_1
5653 - stats_ocacheL1_found_at_N,
5654 stats_ocacheL1_found_at_1 );
5655 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005656 " ocacheL1: %'12lu at 2+ %'12lu move-fwds\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005657 stats_ocacheL1_found_at_N,
5658 stats_ocacheL1_movefwds );
5659 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005660 " ocacheL1: %'12lu sizeB %'12u useful\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005661 (UWord)sizeof(OCache),
5662 4 * OC_W32S_PER_LINE * OC_LINES_PER_SET * OC_N_SETS );
5663 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005664 " ocacheL2: %'12lu refs %'12lu misses\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005665 stats__ocacheL2_refs,
5666 stats__ocacheL2_misses );
5667 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005668 " ocacheL2: %'9lu max nodes %'9lu curr nodes\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005669 stats__ocacheL2_n_nodes_max,
5670 stats__ocacheL2_n_nodes );
5671 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005672 " niacache: %'12lu refs %'12lu misses\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005673 stats__nia_cache_queries, stats__nia_cache_misses);
sewardj9d624d12008-05-02 13:35:29 +00005674 } else {
sewardj77139802008-05-05 09:48:56 +00005675 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005676 tl_assert(ocacheL2 == NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00005677 }
sewardj45d94cc2005-04-20 14:44:11 +00005678 }
5679
njn5c004e42002-11-18 11:04:50 +00005680 if (0) {
5681 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005682 "------ Valgrind's client block stats follow ---------------\n" );
nethercote8b76fe52004-11-08 19:20:09 +00005683 show_client_block_stats();
njn5c004e42002-11-18 11:04:50 +00005684 }
njn25e49d8e72002-09-23 09:36:25 +00005685}
5686
njn51d827b2005-05-09 01:02:08 +00005687static void mc_pre_clo_init(void)
5688{
5689 VG_(details_name) ("Memcheck");
5690 VG_(details_version) (NULL);
5691 VG_(details_description) ("a memory error detector");
5692 VG_(details_copyright_author)(
njn9f207462009-03-10 22:02:09 +00005693 "Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.");
njn51d827b2005-05-09 01:02:08 +00005694 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj05a46732006-10-17 01:28:10 +00005695 VG_(details_avg_translation_sizeB) ( 556 );
njn51d827b2005-05-09 01:02:08 +00005696
5697 VG_(basic_tool_funcs) (mc_post_clo_init,
5698 MC_(instrument),
5699 mc_fini);
5700
sewardj81651dc2007-08-28 06:05:20 +00005701 VG_(needs_final_IR_tidy_pass) ( MC_(final_tidy) );
5702
5703
njn51d827b2005-05-09 01:02:08 +00005704 VG_(needs_core_errors) ();
sewardj7ce71662008-05-02 10:33:15 +00005705 VG_(needs_tool_errors) (MC_(eq_Error),
sewardj6b523cd2009-07-15 14:49:40 +00005706 MC_(before_pp_Error),
sewardj7ce71662008-05-02 10:33:15 +00005707 MC_(pp_Error),
sewardj39f34232007-11-09 23:02:28 +00005708 True,/*show TIDs for errors*/
sewardj7ce71662008-05-02 10:33:15 +00005709 MC_(update_Error_extra),
5710 MC_(is_recognised_suppression),
5711 MC_(read_extra_suppression_info),
5712 MC_(error_matches_suppression),
5713 MC_(get_error_name),
5714 MC_(print_extra_suppression_info));
njn51d827b2005-05-09 01:02:08 +00005715 VG_(needs_libc_freeres) ();
njn1d0825f2006-03-27 11:37:07 +00005716 VG_(needs_command_line_options)(mc_process_cmd_line_options,
njn51d827b2005-05-09 01:02:08 +00005717 mc_print_usage,
5718 mc_print_debug_usage);
5719 VG_(needs_client_requests) (mc_handle_client_request);
5720 VG_(needs_sanity_checks) (mc_cheap_sanity_check,
5721 mc_expensive_sanity_check);
njn1d0825f2006-03-27 11:37:07 +00005722 VG_(needs_malloc_replacement) (MC_(malloc),
5723 MC_(__builtin_new),
5724 MC_(__builtin_vec_new),
5725 MC_(memalign),
5726 MC_(calloc),
5727 MC_(free),
5728 MC_(__builtin_delete),
5729 MC_(__builtin_vec_delete),
5730 MC_(realloc),
njn8b140de2009-02-17 04:31:18 +00005731 MC_(malloc_usable_size),
njn1d0825f2006-03-27 11:37:07 +00005732 MC_MALLOC_REDZONE_SZB );
sewardj6b523cd2009-07-15 14:49:40 +00005733
njnca54af32006-04-16 10:25:43 +00005734 VG_(needs_xml_output) ();
njn51d827b2005-05-09 01:02:08 +00005735
njn1d0825f2006-03-27 11:37:07 +00005736 VG_(track_new_mem_startup) ( mc_new_mem_startup );
sewardj7cf4e6b2008-05-01 20:24:26 +00005737 VG_(track_new_mem_stack_signal)( make_mem_undefined_w_tid );
5738 VG_(track_new_mem_brk) ( make_mem_undefined_w_tid );
njn1d0825f2006-03-27 11:37:07 +00005739 VG_(track_new_mem_mmap) ( mc_new_mem_mmap );
njn51d827b2005-05-09 01:02:08 +00005740
njn1d0825f2006-03-27 11:37:07 +00005741 VG_(track_copy_mem_remap) ( MC_(copy_address_range_state) );
njn81623712005-10-07 04:48:37 +00005742
5743 // Nb: we don't do anything with mprotect. This means that V bits are
5744 // preserved if a program, for example, marks some memory as inaccessible
5745 // and then later marks it as accessible again.
5746 //
5747 // If an access violation occurs (eg. writing to read-only memory) we let
5748 // it fault and print an informative termination message. This doesn't
5749 // happen if the program catches the signal, though, which is bad. If we
5750 // had two A bits (for readability and writability) that were completely
5751 // distinct from V bits, then we could handle all this properly.
5752 VG_(track_change_mem_mprotect) ( NULL );
njn51d827b2005-05-09 01:02:08 +00005753
njndbf7ca72006-03-31 11:57:59 +00005754 VG_(track_die_mem_stack_signal)( MC_(make_mem_noaccess) );
5755 VG_(track_die_mem_brk) ( MC_(make_mem_noaccess) );
5756 VG_(track_die_mem_munmap) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005757
sewardj7cf4e6b2008-05-01 20:24:26 +00005758 /* Defer the specification of the new_mem_stack functions to the
5759 post_clo_init function, since we need to first parse the command
5760 line before deciding which set to use. */
njn51d827b2005-05-09 01:02:08 +00005761
sewardj7cf4e6b2008-05-01 20:24:26 +00005762# ifdef PERF_FAST_STACK
njn1d0825f2006-03-27 11:37:07 +00005763 VG_(track_die_mem_stack_4) ( mc_die_mem_stack_4 );
5764 VG_(track_die_mem_stack_8) ( mc_die_mem_stack_8 );
5765 VG_(track_die_mem_stack_12) ( mc_die_mem_stack_12 );
5766 VG_(track_die_mem_stack_16) ( mc_die_mem_stack_16 );
5767 VG_(track_die_mem_stack_32) ( mc_die_mem_stack_32 );
5768 VG_(track_die_mem_stack_112) ( mc_die_mem_stack_112 );
5769 VG_(track_die_mem_stack_128) ( mc_die_mem_stack_128 );
5770 VG_(track_die_mem_stack_144) ( mc_die_mem_stack_144 );
5771 VG_(track_die_mem_stack_160) ( mc_die_mem_stack_160 );
sewardj7cf4e6b2008-05-01 20:24:26 +00005772# endif
njn1d0825f2006-03-27 11:37:07 +00005773 VG_(track_die_mem_stack) ( mc_die_mem_stack );
njn51d827b2005-05-09 01:02:08 +00005774
njndbf7ca72006-03-31 11:57:59 +00005775 VG_(track_ban_mem_stack) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005776
njndbf7ca72006-03-31 11:57:59 +00005777 VG_(track_pre_mem_read) ( check_mem_is_defined );
5778 VG_(track_pre_mem_read_asciiz) ( check_mem_is_defined_asciiz );
5779 VG_(track_pre_mem_write) ( check_mem_is_addressable );
njn1d0825f2006-03-27 11:37:07 +00005780 VG_(track_post_mem_write) ( mc_post_mem_write );
njn51d827b2005-05-09 01:02:08 +00005781
sewardj7cf4e6b2008-05-01 20:24:26 +00005782 if (MC_(clo_mc_level) >= 2)
njn1d0825f2006-03-27 11:37:07 +00005783 VG_(track_pre_reg_read) ( mc_pre_reg_read );
njn51d827b2005-05-09 01:02:08 +00005784
njn1d0825f2006-03-27 11:37:07 +00005785 VG_(track_post_reg_write) ( mc_post_reg_write );
5786 VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
njn51d827b2005-05-09 01:02:08 +00005787
5788 init_shadow_memory();
sewardj3f94a7d2007-08-25 07:19:08 +00005789 MC_(malloc_list) = VG_(HT_construct)( "MC_(malloc_list)" );
5790 MC_(mempool_list) = VG_(HT_construct)( "MC_(mempool_list)" );
njn1d0825f2006-03-27 11:37:07 +00005791 init_prof_mem();
njn51d827b2005-05-09 01:02:08 +00005792
5793 tl_assert( mc_expensive_sanity_check() );
njn1d0825f2006-03-27 11:37:07 +00005794
5795 // {LOADV,STOREV}[8421] will all fail horribly if this isn't true.
5796 tl_assert(sizeof(UWord) == sizeof(Addr));
sewardj05a46732006-10-17 01:28:10 +00005797 // Call me paranoid. I don't care.
5798 tl_assert(sizeof(void*) == sizeof(Addr));
njn1d0825f2006-03-27 11:37:07 +00005799
5800 // BYTES_PER_SEC_VBIT_NODE must be a power of two.
5801 tl_assert(-1 != VG_(log2)(BYTES_PER_SEC_VBIT_NODE));
sewardj7cf4e6b2008-05-01 20:24:26 +00005802
sewardj9d624d12008-05-02 13:35:29 +00005803 /* This is small. Always initialise it. */
sewardj7cf4e6b2008-05-01 20:24:26 +00005804 init_nia_to_ecu_cache();
sewardj7244e712008-05-02 12:35:48 +00005805
sewardj77139802008-05-05 09:48:56 +00005806 /* We can't initialise ocacheL1/ocacheL2 yet, since we don't know
5807 if we need to, since the command line args haven't been
5808 processed yet. Hence defer it to mc_post_clo_init. */
5809 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005810 tl_assert(ocacheL2 == NULL);
5811
sewardj7244e712008-05-02 12:35:48 +00005812 /* Check some important stuff. See extensive comments above
5813 re UNALIGNED_OR_HIGH for background. */
5814# if VG_WORDSIZE == 4
5815 tl_assert(sizeof(void*) == 4);
5816 tl_assert(sizeof(Addr) == 4);
5817 tl_assert(sizeof(UWord) == 4);
5818 tl_assert(sizeof(Word) == 4);
5819 tl_assert(MAX_PRIMARY_ADDRESS == 0xFFFFFFFFUL);
5820 tl_assert(MASK(1) == 0UL);
5821 tl_assert(MASK(2) == 1UL);
5822 tl_assert(MASK(4) == 3UL);
5823 tl_assert(MASK(8) == 7UL);
5824# else
5825 tl_assert(VG_WORDSIZE == 8);
5826 tl_assert(sizeof(void*) == 8);
5827 tl_assert(sizeof(Addr) == 8);
5828 tl_assert(sizeof(UWord) == 8);
5829 tl_assert(sizeof(Word) == 8);
5830 tl_assert(MAX_PRIMARY_ADDRESS == 0x7FFFFFFFFULL);
5831 tl_assert(MASK(1) == 0xFFFFFFF800000000ULL);
5832 tl_assert(MASK(2) == 0xFFFFFFF800000001ULL);
5833 tl_assert(MASK(4) == 0xFFFFFFF800000003ULL);
5834 tl_assert(MASK(8) == 0xFFFFFFF800000007ULL);
5835# endif
njn51d827b2005-05-09 01:02:08 +00005836}
5837
sewardj45f4e7c2005-09-27 19:20:21 +00005838VG_DETERMINE_INTERFACE_VERSION(mc_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00005839
njn25e49d8e72002-09-23 09:36:25 +00005840/*--------------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00005841/*--- end mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005842/*--------------------------------------------------------------------*/