blob: f62ad47d1c59c3a30f15799dfd2af50cdd920c32 [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
sewardj9eecbbb2010-05-03 21:37:12 +000012 Copyright (C) 2000-2010 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
sewardj6f95e7e2010-01-27 10:28:00 +00001639/* Similarly (needed for mprotect handling ..) */
1640static void make_mem_defined_if_noaccess ( Addr a, SizeT len )
1641{
1642 SizeT i;
1643 UChar vabits2;
1644 DEBUG("make_mem_defined_if_noaccess(%p, %llu)\n", a, (ULong)len);
1645 for (i = 0; i < len; i++) {
1646 vabits2 = get_vabits2( a+i );
1647 if (LIKELY(VA_BITS2_NOACCESS == vabits2)) {
1648 set_vabits2(a+i, VA_BITS2_DEFINED);
1649 if (UNLIKELY(MC_(clo_mc_level) >= 3)) {
1650 MC_(helperc_b_store1)( a+i, 0 ); /* clear the origin tag */
1651 }
1652 }
1653 }
1654}
njn9b007f62003-04-07 14:40:25 +00001655
sewardj45f4e7c2005-09-27 19:20:21 +00001656/* --- Block-copy permissions (needed for implementing realloc() and
1657 sys_mremap). --- */
sewardjc859fbf2005-04-22 21:10:28 +00001658
njn1d0825f2006-03-27 11:37:07 +00001659void MC_(copy_address_range_state) ( Addr src, Addr dst, SizeT len )
sewardjc859fbf2005-04-22 21:10:28 +00001660{
sewardj45f4e7c2005-09-27 19:20:21 +00001661 SizeT i, j;
sewardjf2184912006-05-03 22:13:57 +00001662 UChar vabits2, vabits8;
1663 Bool aligned, nooverlap;
sewardjc859fbf2005-04-22 21:10:28 +00001664
njn1d0825f2006-03-27 11:37:07 +00001665 DEBUG("MC_(copy_address_range_state)\n");
1666 PROF_EVENT(50, "MC_(copy_address_range_state)");
sewardj45f4e7c2005-09-27 19:20:21 +00001667
sewardjf2184912006-05-03 22:13:57 +00001668 if (len == 0 || src == dst)
sewardj45f4e7c2005-09-27 19:20:21 +00001669 return;
1670
sewardjf2184912006-05-03 22:13:57 +00001671 aligned = VG_IS_4_ALIGNED(src) && VG_IS_4_ALIGNED(dst);
1672 nooverlap = src+len <= dst || dst+len <= src;
sewardj45f4e7c2005-09-27 19:20:21 +00001673
sewardjf2184912006-05-03 22:13:57 +00001674 if (nooverlap && aligned) {
1675
1676 /* Vectorised fast case, when no overlap and suitably aligned */
1677 /* vector loop */
1678 i = 0;
1679 while (len >= 4) {
1680 vabits8 = get_vabits8_for_aligned_word32( src+i );
1681 set_vabits8_for_aligned_word32( dst+i, vabits8 );
bart5dd8e6a2008-03-22 08:04:29 +00001682 if (LIKELY(VA_BITS8_DEFINED == vabits8
sewardjf2184912006-05-03 22:13:57 +00001683 || VA_BITS8_UNDEFINED == vabits8
1684 || VA_BITS8_NOACCESS == vabits8)) {
1685 /* do nothing */
1686 } else {
1687 /* have to copy secondary map info */
1688 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+0 ))
1689 set_sec_vbits8( dst+i+0, get_sec_vbits8( src+i+0 ) );
1690 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+1 ))
1691 set_sec_vbits8( dst+i+1, get_sec_vbits8( src+i+1 ) );
1692 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+2 ))
1693 set_sec_vbits8( dst+i+2, get_sec_vbits8( src+i+2 ) );
1694 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+3 ))
1695 set_sec_vbits8( dst+i+3, get_sec_vbits8( src+i+3 ) );
1696 }
1697 i += 4;
1698 len -= 4;
1699 }
1700 /* fixup loop */
1701 while (len >= 1) {
njn1d0825f2006-03-27 11:37:07 +00001702 vabits2 = get_vabits2( src+i );
1703 set_vabits2( dst+i, vabits2 );
njndbf7ca72006-03-31 11:57:59 +00001704 if (VA_BITS2_PARTDEFINED == vabits2) {
njn1d0825f2006-03-27 11:37:07 +00001705 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1706 }
sewardjf2184912006-05-03 22:13:57 +00001707 i++;
1708 len--;
1709 }
1710
1711 } else {
1712
1713 /* We have to do things the slow way */
1714 if (src < dst) {
1715 for (i = 0, j = len-1; i < len; i++, j--) {
1716 PROF_EVENT(51, "MC_(copy_address_range_state)(loop)");
1717 vabits2 = get_vabits2( src+j );
1718 set_vabits2( dst+j, vabits2 );
1719 if (VA_BITS2_PARTDEFINED == vabits2) {
1720 set_sec_vbits8( dst+j, get_sec_vbits8( src+j ) );
1721 }
1722 }
1723 }
1724
1725 if (src > dst) {
1726 for (i = 0; i < len; i++) {
1727 PROF_EVENT(52, "MC_(copy_address_range_state)(loop)");
1728 vabits2 = get_vabits2( src+i );
1729 set_vabits2( dst+i, vabits2 );
1730 if (VA_BITS2_PARTDEFINED == vabits2) {
1731 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1732 }
1733 }
sewardj45f4e7c2005-09-27 19:20:21 +00001734 }
sewardjc859fbf2005-04-22 21:10:28 +00001735 }
sewardjf2184912006-05-03 22:13:57 +00001736
sewardjc859fbf2005-04-22 21:10:28 +00001737}
1738
1739
sewardj7cf4e6b2008-05-01 20:24:26 +00001740/*------------------------------------------------------------*/
1741/*--- Origin tracking stuff - cache basics ---*/
1742/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00001743
sewardj77139802008-05-05 09:48:56 +00001744/* AN OVERVIEW OF THE ORIGIN TRACKING IMPLEMENTATION
1745 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sewardj7cf4e6b2008-05-01 20:24:26 +00001746
1747 Note that this implementation draws inspiration from the "origin
1748 tracking by value piggybacking" scheme described in "Tracking Bad
1749 Apples: Reporting the Origin of Null and Undefined Value Errors"
1750 (Michael Bond, Nicholas Nethercote, Stephen Kent, Samuel Guyer,
1751 Kathryn McKinley, OOPSLA07, Montreal, Oct 2007) but in fact it is
1752 implemented completely differently.
1753
sewardj77139802008-05-05 09:48:56 +00001754 Origin tags and ECUs -- about the shadow values
1755 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1756
1757 This implementation tracks the defining point of all uninitialised
1758 values using so called "origin tags", which are 32-bit integers,
1759 rather than using the values themselves to encode the origins. The
1760 latter, so-called value piggybacking", is what the OOPSLA07 paper
sewardj7cf4e6b2008-05-01 20:24:26 +00001761 describes.
1762
1763 Origin tags, as tracked by the machinery below, are 32-bit unsigned
sewardj77139802008-05-05 09:48:56 +00001764 ints (UInts), regardless of the machine's word size. Each tag
1765 comprises an upper 30-bit ECU field and a lower 2-bit
1766 'kind' field. The ECU field is a number given out by m_execontext
1767 and has a 1-1 mapping with ExeContext*s. An ECU can be used
1768 directly as an origin tag (otag), but in fact we want to put
1769 additional information 'kind' field to indicate roughly where the
1770 tag came from. This helps print more understandable error messages
1771 for the user -- it has no other purpose. In summary:
1772
1773 * Both ECUs and origin tags are represented as 32-bit words
1774
1775 * m_execontext and the core-tool interface deal purely in ECUs.
1776 They have no knowledge of origin tags - that is a purely
1777 Memcheck-internal matter.
1778
1779 * all valid ECUs have the lowest 2 bits zero and at least
1780 one of the upper 30 bits nonzero (see VG_(is_plausible_ECU))
1781
1782 * to convert from an ECU to an otag, OR in one of the MC_OKIND_
1783 constants defined in mc_include.h.
1784
1785 * to convert an otag back to an ECU, AND it with ~3
1786
1787 One important fact is that no valid otag is zero. A zero otag is
1788 used by the implementation to indicate "no origin", which could
1789 mean that either the value is defined, or it is undefined but the
1790 implementation somehow managed to lose the origin.
1791
1792 The ECU used for memory created by malloc etc is derived from the
1793 stack trace at the time the malloc etc happens. This means the
1794 mechanism can show the exact allocation point for heap-created
1795 uninitialised values.
1796
1797 In contrast, it is simply too expensive to create a complete
1798 backtrace for each stack allocation. Therefore we merely use a
1799 depth-1 backtrace for stack allocations, which can be done once at
1800 translation time, rather than N times at run time. The result of
1801 this is that, for stack created uninitialised values, Memcheck can
1802 only show the allocating function, and not what called it.
1803 Furthermore, compilers tend to move the stack pointer just once at
1804 the start of the function, to allocate all locals, and so in fact
1805 the stack origin almost always simply points to the opening brace
1806 of the function. Net result is, for stack origins, the mechanism
1807 can tell you in which function the undefined value was created, but
1808 that's all. Users will need to carefully check all locals in the
1809 specified function.
1810
1811 Shadowing registers and memory
1812 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1813
1814 Memory is shadowed using a two level cache structure (ocacheL1 and
1815 ocacheL2). Memory references are first directed to ocacheL1. This
1816 is a traditional 2-way set associative cache with 32-byte lines and
1817 approximate LRU replacement within each set.
1818
1819 A naive implementation would require storing one 32 bit otag for
1820 each byte of memory covered, a 4:1 space overhead. Instead, there
1821 is one otag for every 4 bytes of memory covered, plus a 4-bit mask
1822 that shows which of the 4 bytes have that shadow value and which
1823 have a shadow value of zero (indicating no origin). Hence a lot of
1824 space is saved, but the cost is that only one different origin per
1825 4 bytes of address space can be represented. This is a source of
1826 imprecision, but how much of a problem it really is remains to be
1827 seen.
1828
1829 A cache line that contains all zeroes ("no origins") contains no
1830 useful information, and can be ejected from the L1 cache "for
1831 free", in the sense that a read miss on the L1 causes a line of
1832 zeroes to be installed. However, ejecting a line containing
1833 nonzeroes risks losing origin information permanently. In order to
1834 prevent such lossage, ejected nonzero lines are placed in a
1835 secondary cache (ocacheL2), which is an OSet (AVL tree) of cache
1836 lines. This can grow arbitrarily large, and so should ensure that
1837 Memcheck runs out of memory in preference to losing useful origin
1838 info due to cache size limitations.
1839
1840 Shadowing registers is a bit tricky, because the shadow values are
1841 32 bits, regardless of the size of the register. That gives a
1842 problem for registers smaller than 32 bits. The solution is to
1843 find spaces in the guest state that are unused, and use those to
1844 shadow guest state fragments smaller than 32 bits. For example, on
1845 ppc32/64, each vector register is 16 bytes long. If 4 bytes of the
1846 shadow are allocated for the register's otag, then there are still
1847 12 bytes left over which could be used to shadow 3 other values.
1848
1849 This implies there is some non-obvious mapping from guest state
1850 (start,length) pairs to the relevant shadow offset (for the origin
1851 tags). And it is unfortunately guest-architecture specific. The
1852 mapping is contained in mc_machine.c, which is quite lengthy but
1853 straightforward.
1854
1855 Instrumenting the IR
1856 ~~~~~~~~~~~~~~~~~~~~
1857
1858 Instrumentation is largely straightforward, and done by the
1859 functions schemeE and schemeS in mc_translate.c. These generate
1860 code for handling the origin tags of expressions (E) and statements
1861 (S) respectively. The rather strange names are a reference to the
1862 "compilation schemes" shown in Simon Peyton Jones' book "The
1863 Implementation of Functional Programming Languages" (Prentice Hall,
1864 1987, see
1865 http://research.microsoft.com/~simonpj/papers/slpj-book-1987/index.htm).
1866
1867 schemeS merely arranges to move shadow values around the guest
1868 state to track the incoming IR. schemeE is largely trivial too.
1869 The only significant point is how to compute the otag corresponding
1870 to binary (or ternary, quaternary, etc) operator applications. The
1871 rule is simple: just take whichever value is larger (32-bit
1872 unsigned max). Constants get the special value zero. Hence this
1873 rule always propagates a nonzero (known) otag in preference to a
1874 zero (unknown, or more likely, value-is-defined) tag, as we want.
1875 If two different undefined values are inputs to a binary operator
1876 application, then which is propagated is arbitrary, but that
1877 doesn't matter, since the program is erroneous in using either of
1878 the values, and so there's no point in attempting to propagate
1879 both.
1880
1881 Since constants are abstracted to (otag) zero, much of the
1882 instrumentation code can be folded out without difficulty by the
1883 generic post-instrumentation IR cleanup pass, using these rules:
1884 Max32U(0,x) -> x, Max32U(x,0) -> x, Max32(x,y) where x and y are
1885 constants is evaluated at JIT time. And the resulting dead code
1886 removal. In practice this causes surprisingly few Max32Us to
1887 survive through to backend code generation.
1888
1889 Integration with the V-bits machinery
1890 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1891
1892 This is again largely straightforward. Mostly the otag and V bits
1893 stuff are independent. The only point of interaction is when the V
1894 bits instrumenter creates a call to a helper function to report an
1895 uninitialised value error -- in that case it must first use schemeE
1896 to get hold of the origin tag expression for the value, and pass
1897 that to the helper too.
1898
1899 There is the usual stuff to do with setting address range
1900 permissions. When memory is painted undefined, we must also know
1901 the origin tag to paint with, which involves some tedious plumbing,
1902 particularly to do with the fast case stack handlers. When memory
1903 is painted defined or noaccess then the origin tags must be forced
1904 to zero.
1905
1906 One of the goals of the implementation was to ensure that the
1907 non-origin tracking mode isn't slowed down at all. To do this,
1908 various functions to do with memory permissions setting (again,
1909 mostly pertaining to the stack) are duplicated for the with- and
1910 without-otag case.
1911
1912 Dealing with stack redzones, and the NIA cache
1913 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1914
1915 This is one of the few non-obvious parts of the implementation.
1916
1917 Some ABIs (amd64-ELF, ppc64-ELF, ppc32/64-XCOFF) define a small
1918 reserved area below the stack pointer, that can be used as scratch
1919 space by compiler generated code for functions. In the Memcheck
1920 sources this is referred to as the "stack redzone". The important
1921 thing here is that such redzones are considered volatile across
1922 function calls and returns. So Memcheck takes care to mark them as
1923 undefined for each call and return, on the afflicted platforms.
1924 Past experience shows this is essential in order to get reliable
1925 messages about uninitialised values that come from the stack.
1926
1927 So the question is, when we paint a redzone undefined, what origin
1928 tag should we use for it? Consider a function f() calling g(). If
1929 we paint the redzone using an otag derived from the ExeContext of
1930 the CALL/BL instruction in f, then any errors in g causing it to
1931 use uninitialised values that happen to lie in the redzone, will be
1932 reported as having their origin in f. Which is highly confusing.
1933
1934 The same applies for returns: if, on a return, we paint the redzone
1935 using a origin tag derived from the ExeContext of the RET/BLR
1936 instruction in g, then any later errors in f causing it to use
1937 uninitialised values in the redzone, will be reported as having
1938 their origin in g. Which is just as confusing.
1939
1940 To do it right, in both cases we need to use an origin tag which
1941 pertains to the instruction which dynamically follows the CALL/BL
1942 or RET/BLR. In short, one derived from the NIA - the "next
1943 instruction address".
1944
1945 To make this work, Memcheck's redzone-painting helper,
1946 MC_(helperc_MAKE_STACK_UNINIT), now takes a third argument, the
1947 NIA. It converts the NIA to a 1-element ExeContext, and uses that
1948 ExeContext's ECU as the basis for the otag used to paint the
1949 redzone. The expensive part of this is converting an NIA into an
1950 ECU, since this happens once for every call and every return. So
1951 we use a simple 511-line, 2-way set associative cache
1952 (nia_to_ecu_cache) to cache the mappings, and that knocks most of
1953 the cost out.
1954
1955 Further background comments
1956 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
sewardj7cf4e6b2008-05-01 20:24:26 +00001957
1958 > Question: why is otag a UInt? Wouldn't a UWord be better? Isn't
1959 > it really just the address of the relevant ExeContext?
1960
1961 Well, it's not the address, but a value which has a 1-1 mapping
1962 with ExeContexts, and is guaranteed not to be zero, since zero
1963 denotes (to memcheck) "unknown origin or defined value". So these
sewardj77139802008-05-05 09:48:56 +00001964 UInts are just numbers starting at 4 and incrementing by 4; each
1965 ExeContext is given a number when it is created. (*** NOTE this
1966 confuses otags and ECUs; see comments above ***).
sewardj7cf4e6b2008-05-01 20:24:26 +00001967
1968 Making these otags 32-bit regardless of the machine's word size
1969 makes the 64-bit implementation easier (next para). And it doesn't
1970 really limit us in any way, since for the tags to overflow would
sewardj77139802008-05-05 09:48:56 +00001971 require that the program somehow caused 2^30-1 different
sewardj7cf4e6b2008-05-01 20:24:26 +00001972 ExeContexts to be created, in which case it is probably in deep
1973 trouble. Not to mention V will have soaked up many tens of
1974 gigabytes of memory merely to store them all.
1975
1976 So having 64-bit origins doesn't really buy you anything, and has
1977 the following downsides:
1978
1979 Suppose that instead, an otag is a UWord. This would mean that, on
1980 a 64-bit target,
1981
1982 1. It becomes hard to shadow any element of guest state which is
1983 smaller than 8 bytes. To do so means you'd need to find some
1984 8-byte-sized hole in the guest state which you don't want to
1985 shadow, and use that instead to hold the otag. On ppc64, the
1986 condition code register(s) are split into 20 UChar sized pieces,
1987 all of which need to be tracked (guest_XER_SO .. guest_CR7_0)
1988 and so that would entail finding 160 bytes somewhere else in the
1989 guest state.
1990
1991 Even on x86, I want to track origins for %AH .. %DH (bits 15:8
1992 of %EAX .. %EDX) that are separate from %AL .. %DL (bits 7:0 of
1993 same) and so I had to look for 4 untracked otag-sized areas in
1994 the guest state to make that possible.
1995
1996 The same problem exists of course when origin tags are only 32
1997 bits, but it's less extreme.
1998
1999 2. (More compelling) it doubles the size of the origin shadow
2000 memory. Given that the shadow memory is organised as a fixed
2001 size cache, and that accuracy of tracking is limited by origins
2002 falling out the cache due to space conflicts, this isn't good.
2003
2004 > Another question: is the origin tracking perfect, or are there
2005 > cases where it fails to determine an origin?
2006
2007 It is imperfect for at least for the following reasons, and
2008 probably more:
2009
2010 * Insufficient capacity in the origin cache. When a line is
2011 evicted from the cache it is gone forever, and so subsequent
2012 queries for the line produce zero, indicating no origin
2013 information. Interestingly, a line containing all zeroes can be
2014 evicted "free" from the cache, since it contains no useful
2015 information, so there is scope perhaps for some cleverer cache
sewardj77139802008-05-05 09:48:56 +00002016 management schemes. (*** NOTE, with the introduction of the
2017 second level origin tag cache, ocacheL2, this is no longer a
2018 problem. ***)
sewardj7cf4e6b2008-05-01 20:24:26 +00002019
2020 * The origin cache only stores one otag per 32-bits of address
2021 space, plus 4 bits indicating which of the 4 bytes has that tag
2022 and which are considered defined. The result is that if two
2023 undefined bytes in the same word are stored in memory, the first
2024 stored byte's origin will be lost and replaced by the origin for
2025 the second byte.
2026
2027 * Nonzero origin tags for defined values. Consider a binary
2028 operator application op(x,y). Suppose y is undefined (and so has
2029 a valid nonzero origin tag), and x is defined, but erroneously
2030 has a nonzero origin tag (defined values should have tag zero).
2031 If the erroneous tag has a numeric value greater than y's tag,
2032 then the rule for propagating origin tags though binary
2033 operations, which is simply to take the unsigned max of the two
2034 tags, will erroneously propagate x's tag rather than y's.
2035
2036 * Some obscure uses of x86/amd64 byte registers can cause lossage
2037 or confusion of origins. %AH .. %DH are treated as different
2038 from, and unrelated to, their parent registers, %EAX .. %EDX.
2039 So some wierd sequences like
2040
2041 movb undefined-value, %AH
2042 movb defined-value, %AL
2043 .. use %AX or %EAX ..
2044
2045 will cause the origin attributed to %AH to be ignored, since %AL,
2046 %AX, %EAX are treated as the same register, and %AH as a
2047 completely separate one.
2048
2049 But having said all that, it actually seems to work fairly well in
2050 practice.
2051*/
2052
2053static UWord stats_ocacheL1_find = 0;
2054static UWord stats_ocacheL1_found_at_1 = 0;
2055static UWord stats_ocacheL1_found_at_N = 0;
2056static UWord stats_ocacheL1_misses = 0;
2057static UWord stats_ocacheL1_lossage = 0;
2058static UWord stats_ocacheL1_movefwds = 0;
2059
2060static UWord stats__ocacheL2_refs = 0;
2061static UWord stats__ocacheL2_misses = 0;
2062static UWord stats__ocacheL2_n_nodes_max = 0;
2063
2064/* Cache of 32-bit values, one every 32 bits of address space */
2065
2066#define OC_BITS_PER_LINE 5
2067#define OC_W32S_PER_LINE (1 << (OC_BITS_PER_LINE - 2))
2068
2069static INLINE UWord oc_line_offset ( Addr a ) {
2070 return (a >> 2) & (OC_W32S_PER_LINE - 1);
2071}
2072static INLINE Bool is_valid_oc_tag ( Addr tag ) {
2073 return 0 == (tag & ((1 << OC_BITS_PER_LINE) - 1));
2074}
2075
2076#define OC_LINES_PER_SET 2
2077
2078#define OC_N_SET_BITS 20
2079#define OC_N_SETS (1 << OC_N_SET_BITS)
2080
2081/* These settings give:
2082 64 bit host: ocache: 100,663,296 sizeB 67,108,864 useful
2083 32 bit host: ocache: 92,274,688 sizeB 67,108,864 useful
2084*/
2085
2086#define OC_MOVE_FORWARDS_EVERY_BITS 7
2087
2088
2089typedef
2090 struct {
2091 Addr tag;
2092 UInt w32[OC_W32S_PER_LINE];
2093 UChar descr[OC_W32S_PER_LINE];
2094 }
2095 OCacheLine;
2096
2097/* Classify and also sanity-check 'line'. Return 'e' (empty) if not
2098 in use, 'n' (nonzero) if it contains at least one valid origin tag,
2099 and 'z' if all the represented tags are zero. */
2100static UChar classify_OCacheLine ( OCacheLine* line )
2101{
2102 UWord i;
2103 if (line->tag == 1/*invalid*/)
2104 return 'e'; /* EMPTY */
2105 tl_assert(is_valid_oc_tag(line->tag));
2106 for (i = 0; i < OC_W32S_PER_LINE; i++) {
2107 tl_assert(0 == ((~0xF) & line->descr[i]));
2108 if (line->w32[i] > 0 && line->descr[i] > 0)
2109 return 'n'; /* NONZERO - contains useful info */
2110 }
2111 return 'z'; /* ZERO - no useful info */
2112}
2113
2114typedef
2115 struct {
2116 OCacheLine line[OC_LINES_PER_SET];
2117 }
2118 OCacheSet;
2119
2120typedef
2121 struct {
2122 OCacheSet set[OC_N_SETS];
2123 }
2124 OCache;
2125
sewardj77139802008-05-05 09:48:56 +00002126static OCache* ocacheL1 = NULL;
2127static UWord ocacheL1_event_ctr = 0;
sewardj7cf4e6b2008-05-01 20:24:26 +00002128
2129static void init_ocacheL2 ( void ); /* fwds */
2130static void init_OCache ( void )
2131{
2132 UWord line, set;
sewardj9d624d12008-05-02 13:35:29 +00002133 tl_assert(MC_(clo_mc_level) >= 3);
sewardj77139802008-05-05 09:48:56 +00002134 tl_assert(ocacheL1 == NULL);
2135 ocacheL1 = VG_(am_shadow_alloc)(sizeof(OCache));
2136 if (ocacheL1 == NULL) {
2137 VG_(out_of_memory_NORETURN)( "memcheck:allocating ocacheL1",
sewardj9d624d12008-05-02 13:35:29 +00002138 sizeof(OCache) );
2139 }
sewardj77139802008-05-05 09:48:56 +00002140 tl_assert(ocacheL1 != NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00002141 for (set = 0; set < OC_N_SETS; set++) {
2142 for (line = 0; line < OC_LINES_PER_SET; line++) {
sewardj77139802008-05-05 09:48:56 +00002143 ocacheL1->set[set].line[line].tag = 1/*invalid*/;
sewardj7cf4e6b2008-05-01 20:24:26 +00002144 }
2145 }
2146 init_ocacheL2();
2147}
2148
2149static void moveLineForwards ( OCacheSet* set, UWord lineno )
2150{
2151 OCacheLine tmp;
2152 stats_ocacheL1_movefwds++;
2153 tl_assert(lineno > 0 && lineno < OC_LINES_PER_SET);
2154 tmp = set->line[lineno-1];
2155 set->line[lineno-1] = set->line[lineno];
2156 set->line[lineno] = tmp;
2157}
2158
2159static void zeroise_OCacheLine ( OCacheLine* line, Addr tag ) {
2160 UWord i;
2161 for (i = 0; i < OC_W32S_PER_LINE; i++) {
2162 line->w32[i] = 0; /* NO ORIGIN */
2163 line->descr[i] = 0; /* REALLY REALLY NO ORIGIN! */
2164 }
2165 line->tag = tag;
2166}
2167
2168//////////////////////////////////////////////////////////////
2169//// OCache backing store
2170
2171static OSet* ocacheL2 = NULL;
2172
sewardj9c606bd2008-09-18 18:12:50 +00002173static void* ocacheL2_malloc ( HChar* cc, SizeT szB ) {
2174 return VG_(malloc)(cc, szB);
sewardj7cf4e6b2008-05-01 20:24:26 +00002175}
2176static void ocacheL2_free ( void* v ) {
2177 VG_(free)( v );
2178}
2179
2180/* Stats: # nodes currently in tree */
2181static UWord stats__ocacheL2_n_nodes = 0;
2182
2183static void init_ocacheL2 ( void )
2184{
2185 tl_assert(!ocacheL2);
2186 tl_assert(sizeof(Word) == sizeof(Addr)); /* since OCacheLine.tag :: Addr */
2187 tl_assert(0 == offsetof(OCacheLine,tag));
2188 ocacheL2
2189 = VG_(OSetGen_Create)( offsetof(OCacheLine,tag),
2190 NULL, /* fast cmp */
sewardj9c606bd2008-09-18 18:12:50 +00002191 ocacheL2_malloc, "mc.ioL2", ocacheL2_free );
sewardj7cf4e6b2008-05-01 20:24:26 +00002192 tl_assert(ocacheL2);
2193 stats__ocacheL2_n_nodes = 0;
2194}
2195
2196/* Find line with the given tag in the tree, or NULL if not found. */
2197static OCacheLine* ocacheL2_find_tag ( Addr tag )
2198{
2199 OCacheLine* line;
2200 tl_assert(is_valid_oc_tag(tag));
2201 stats__ocacheL2_refs++;
2202 line = VG_(OSetGen_Lookup)( ocacheL2, &tag );
2203 return line;
2204}
2205
2206/* Delete the line with the given tag from the tree, if it is present, and
2207 free up the associated memory. */
2208static void ocacheL2_del_tag ( Addr tag )
2209{
2210 OCacheLine* line;
2211 tl_assert(is_valid_oc_tag(tag));
2212 stats__ocacheL2_refs++;
2213 line = VG_(OSetGen_Remove)( ocacheL2, &tag );
2214 if (line) {
2215 VG_(OSetGen_FreeNode)(ocacheL2, line);
2216 tl_assert(stats__ocacheL2_n_nodes > 0);
2217 stats__ocacheL2_n_nodes--;
2218 }
2219}
2220
2221/* Add a copy of the given line to the tree. It must not already be
2222 present. */
2223static void ocacheL2_add_line ( OCacheLine* line )
2224{
2225 OCacheLine* copy;
2226 tl_assert(is_valid_oc_tag(line->tag));
2227 copy = VG_(OSetGen_AllocNode)( ocacheL2, sizeof(OCacheLine) );
2228 tl_assert(copy);
2229 *copy = *line;
2230 stats__ocacheL2_refs++;
2231 VG_(OSetGen_Insert)( ocacheL2, copy );
2232 stats__ocacheL2_n_nodes++;
2233 if (stats__ocacheL2_n_nodes > stats__ocacheL2_n_nodes_max)
2234 stats__ocacheL2_n_nodes_max = stats__ocacheL2_n_nodes;
2235}
2236
2237////
2238//////////////////////////////////////////////////////////////
2239
2240__attribute__((noinline))
2241static OCacheLine* find_OCacheLine_SLOW ( Addr a )
2242{
2243 OCacheLine *victim, *inL2;
2244 UChar c;
2245 UWord line;
2246 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2247 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2248 UWord tag = a & tagmask;
2249 tl_assert(setno >= 0 && setno < OC_N_SETS);
2250
2251 /* we already tried line == 0; skip therefore. */
2252 for (line = 1; line < OC_LINES_PER_SET; line++) {
sewardj77139802008-05-05 09:48:56 +00002253 if (ocacheL1->set[setno].line[line].tag == tag) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002254 if (line == 1) {
2255 stats_ocacheL1_found_at_1++;
2256 } else {
2257 stats_ocacheL1_found_at_N++;
2258 }
sewardj77139802008-05-05 09:48:56 +00002259 if (UNLIKELY(0 == (ocacheL1_event_ctr++
sewardj7cf4e6b2008-05-01 20:24:26 +00002260 & ((1<<OC_MOVE_FORWARDS_EVERY_BITS)-1)))) {
sewardj77139802008-05-05 09:48:56 +00002261 moveLineForwards( &ocacheL1->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002262 line--;
2263 }
sewardj77139802008-05-05 09:48:56 +00002264 return &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002265 }
2266 }
2267
2268 /* A miss. Use the last slot. Implicitly this means we're
2269 ejecting the line in the last slot. */
2270 stats_ocacheL1_misses++;
2271 tl_assert(line == OC_LINES_PER_SET);
2272 line--;
2273 tl_assert(line > 0);
2274
2275 /* First, move the to-be-ejected line to the L2 cache. */
sewardj77139802008-05-05 09:48:56 +00002276 victim = &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002277 c = classify_OCacheLine(victim);
2278 switch (c) {
2279 case 'e':
2280 /* the line is empty (has invalid tag); ignore it. */
2281 break;
2282 case 'z':
2283 /* line contains zeroes. We must ensure the backing store is
2284 updated accordingly, either by copying the line there
2285 verbatim, or by ensuring it isn't present there. We
2286 chosse the latter on the basis that it reduces the size of
2287 the backing store. */
2288 ocacheL2_del_tag( victim->tag );
2289 break;
2290 case 'n':
2291 /* line contains at least one real, useful origin. Copy it
2292 to the backing store. */
2293 stats_ocacheL1_lossage++;
2294 inL2 = ocacheL2_find_tag( victim->tag );
2295 if (inL2) {
2296 *inL2 = *victim;
2297 } else {
2298 ocacheL2_add_line( victim );
2299 }
2300 break;
2301 default:
2302 tl_assert(0);
2303 }
2304
2305 /* Now we must reload the L1 cache from the backing tree, if
2306 possible. */
2307 tl_assert(tag != victim->tag); /* stay sane */
2308 inL2 = ocacheL2_find_tag( tag );
2309 if (inL2) {
2310 /* We're in luck. It's in the L2. */
sewardj77139802008-05-05 09:48:56 +00002311 ocacheL1->set[setno].line[line] = *inL2;
sewardj7cf4e6b2008-05-01 20:24:26 +00002312 } else {
2313 /* Missed at both levels of the cache hierarchy. We have to
2314 declare it as full of zeroes (unknown origins). */
2315 stats__ocacheL2_misses++;
sewardj77139802008-05-05 09:48:56 +00002316 zeroise_OCacheLine( &ocacheL1->set[setno].line[line], tag );
sewardj7cf4e6b2008-05-01 20:24:26 +00002317 }
2318
2319 /* Move it one forwards */
sewardj77139802008-05-05 09:48:56 +00002320 moveLineForwards( &ocacheL1->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002321 line--;
2322
sewardj77139802008-05-05 09:48:56 +00002323 return &ocacheL1->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002324}
2325
2326static INLINE OCacheLine* find_OCacheLine ( Addr a )
2327{
2328 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2329 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2330 UWord tag = a & tagmask;
2331
2332 stats_ocacheL1_find++;
2333
2334 if (OC_ENABLE_ASSERTIONS) {
2335 tl_assert(setno >= 0 && setno < OC_N_SETS);
2336 tl_assert(0 == (tag & (4 * OC_W32S_PER_LINE - 1)));
2337 }
2338
sewardj77139802008-05-05 09:48:56 +00002339 if (LIKELY(ocacheL1->set[setno].line[0].tag == tag)) {
2340 return &ocacheL1->set[setno].line[0];
sewardj7cf4e6b2008-05-01 20:24:26 +00002341 }
2342
2343 return find_OCacheLine_SLOW( a );
2344}
2345
2346static INLINE void set_aligned_word64_Origin_to_undef ( Addr a, UInt otag )
2347{
2348 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2349 //// Set the origins for a+0 .. a+7
2350 { OCacheLine* line;
2351 UWord lineoff = oc_line_offset(a);
2352 if (OC_ENABLE_ASSERTIONS) {
2353 tl_assert(lineoff >= 0
2354 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2355 }
2356 line = find_OCacheLine( a );
2357 line->descr[lineoff+0] = 0xF;
2358 line->descr[lineoff+1] = 0xF;
2359 line->w32[lineoff+0] = otag;
2360 line->w32[lineoff+1] = otag;
2361 }
2362 //// END inlined, specialised version of MC_(helperc_b_store8)
2363}
2364
2365
2366/*------------------------------------------------------------*/
2367/*--- Aligned fast case permission setters, ---*/
2368/*--- for dealing with stacks ---*/
2369/*------------------------------------------------------------*/
2370
2371/*--------------------- 32-bit ---------------------*/
2372
2373/* Nb: by "aligned" here we mean 4-byte aligned */
2374
2375static INLINE void make_aligned_word32_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002376{
njndbf7ca72006-03-31 11:57:59 +00002377 PROF_EVENT(300, "make_aligned_word32_undefined");
sewardj5d28efc2005-04-21 22:16:29 +00002378
njn1d0825f2006-03-27 11:37:07 +00002379#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002380 make_mem_undefined(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002381#else
njneccf7c02009-01-19 23:42:45 +00002382 {
2383 UWord sm_off;
2384 SecMap* sm;
sewardj5d28efc2005-04-21 22:16:29 +00002385
njneccf7c02009-01-19 23:42:45 +00002386 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2387 PROF_EVENT(301, "make_aligned_word32_undefined-slow1");
2388 make_mem_undefined(a, 4);
2389 return;
2390 }
2391
2392 sm = get_secmap_for_writing_low(a);
2393 sm_off = SM_OFF(a);
2394 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
2395 }
njn1d0825f2006-03-27 11:37:07 +00002396#endif
njn9b007f62003-04-07 14:40:25 +00002397}
2398
sewardj7cf4e6b2008-05-01 20:24:26 +00002399static INLINE
2400void make_aligned_word32_undefined_w_otag ( Addr a, UInt otag )
2401{
2402 make_aligned_word32_undefined(a);
2403 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2404 //// Set the origins for a+0 .. a+3
2405 { OCacheLine* line;
2406 UWord lineoff = oc_line_offset(a);
2407 if (OC_ENABLE_ASSERTIONS) {
2408 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2409 }
2410 line = find_OCacheLine( a );
2411 line->descr[lineoff] = 0xF;
2412 line->w32[lineoff] = otag;
2413 }
2414 //// END inlined, specialised version of MC_(helperc_b_store4)
2415}
sewardj5d28efc2005-04-21 22:16:29 +00002416
njn1d0825f2006-03-27 11:37:07 +00002417static INLINE
2418void make_aligned_word32_noaccess ( Addr a )
sewardj5d28efc2005-04-21 22:16:29 +00002419{
2420 PROF_EVENT(310, "make_aligned_word32_noaccess");
2421
njn1d0825f2006-03-27 11:37:07 +00002422#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002423 MC_(make_mem_noaccess)(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002424#else
njneccf7c02009-01-19 23:42:45 +00002425 {
2426 UWord sm_off;
2427 SecMap* sm;
sewardj5d28efc2005-04-21 22:16:29 +00002428
njneccf7c02009-01-19 23:42:45 +00002429 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2430 PROF_EVENT(311, "make_aligned_word32_noaccess-slow1");
2431 MC_(make_mem_noaccess)(a, 4);
2432 return;
sewardj7cf4e6b2008-05-01 20:24:26 +00002433 }
njneccf7c02009-01-19 23:42:45 +00002434
2435 sm = get_secmap_for_writing_low(a);
2436 sm_off = SM_OFF(a);
2437 sm->vabits8[sm_off] = VA_BITS8_NOACCESS;
2438
2439 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2440 //// Set the origins for a+0 .. a+3.
2441 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2442 OCacheLine* line;
2443 UWord lineoff = oc_line_offset(a);
2444 if (OC_ENABLE_ASSERTIONS) {
2445 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2446 }
2447 line = find_OCacheLine( a );
2448 line->descr[lineoff] = 0;
2449 }
2450 //// END inlined, specialised version of MC_(helperc_b_store4)
sewardj7cf4e6b2008-05-01 20:24:26 +00002451 }
njn1d0825f2006-03-27 11:37:07 +00002452#endif
sewardj5d28efc2005-04-21 22:16:29 +00002453}
2454
sewardj7cf4e6b2008-05-01 20:24:26 +00002455/*--------------------- 64-bit ---------------------*/
sewardj5d28efc2005-04-21 22:16:29 +00002456
njn9b007f62003-04-07 14:40:25 +00002457/* Nb: by "aligned" here we mean 8-byte aligned */
sewardj7cf4e6b2008-05-01 20:24:26 +00002458
2459static INLINE void make_aligned_word64_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002460{
njndbf7ca72006-03-31 11:57:59 +00002461 PROF_EVENT(320, "make_aligned_word64_undefined");
sewardj23eb2fd2005-04-22 16:29:19 +00002462
njn1d0825f2006-03-27 11:37:07 +00002463#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002464 make_mem_undefined(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002465#else
njneccf7c02009-01-19 23:42:45 +00002466 {
2467 UWord sm_off16;
2468 SecMap* sm;
sewardj23eb2fd2005-04-22 16:29:19 +00002469
njneccf7c02009-01-19 23:42:45 +00002470 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2471 PROF_EVENT(321, "make_aligned_word64_undefined-slow1");
2472 make_mem_undefined(a, 8);
2473 return;
2474 }
2475
2476 sm = get_secmap_for_writing_low(a);
2477 sm_off16 = SM_OFF_16(a);
2478 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_UNDEFINED;
2479 }
njn1d0825f2006-03-27 11:37:07 +00002480#endif
njn9b007f62003-04-07 14:40:25 +00002481}
2482
sewardj7cf4e6b2008-05-01 20:24:26 +00002483static INLINE
2484void make_aligned_word64_undefined_w_otag ( Addr a, UInt otag )
2485{
2486 make_aligned_word64_undefined(a);
2487 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2488 //// Set the origins for a+0 .. a+7
2489 { OCacheLine* line;
2490 UWord lineoff = oc_line_offset(a);
2491 tl_assert(lineoff >= 0
2492 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2493 line = find_OCacheLine( a );
2494 line->descr[lineoff+0] = 0xF;
2495 line->descr[lineoff+1] = 0xF;
2496 line->w32[lineoff+0] = otag;
2497 line->w32[lineoff+1] = otag;
2498 }
2499 //// END inlined, specialised version of MC_(helperc_b_store8)
2500}
sewardj23eb2fd2005-04-22 16:29:19 +00002501
njn1d0825f2006-03-27 11:37:07 +00002502static INLINE
2503void make_aligned_word64_noaccess ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002504{
sewardj23eb2fd2005-04-22 16:29:19 +00002505 PROF_EVENT(330, "make_aligned_word64_noaccess");
2506
njn1d0825f2006-03-27 11:37:07 +00002507#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002508 MC_(make_mem_noaccess)(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002509#else
njneccf7c02009-01-19 23:42:45 +00002510 {
2511 UWord sm_off16;
2512 SecMap* sm;
sewardj23eb2fd2005-04-22 16:29:19 +00002513
njneccf7c02009-01-19 23:42:45 +00002514 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
2515 PROF_EVENT(331, "make_aligned_word64_noaccess-slow1");
2516 MC_(make_mem_noaccess)(a, 8);
2517 return;
2518 }
sewardj7cf4e6b2008-05-01 20:24:26 +00002519
njneccf7c02009-01-19 23:42:45 +00002520 sm = get_secmap_for_writing_low(a);
2521 sm_off16 = SM_OFF_16(a);
2522 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_NOACCESS;
2523
2524 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2525 //// Clear the origins for a+0 .. a+7.
2526 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2527 OCacheLine* line;
2528 UWord lineoff = oc_line_offset(a);
2529 tl_assert(lineoff >= 0
2530 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2531 line = find_OCacheLine( a );
2532 line->descr[lineoff+0] = 0;
2533 line->descr[lineoff+1] = 0;
2534 }
2535 //// END inlined, specialised version of MC_(helperc_b_store8)
sewardj7cf4e6b2008-05-01 20:24:26 +00002536 }
njn1d0825f2006-03-27 11:37:07 +00002537#endif
njn9b007f62003-04-07 14:40:25 +00002538}
2539
sewardj23eb2fd2005-04-22 16:29:19 +00002540
njn1d0825f2006-03-27 11:37:07 +00002541/*------------------------------------------------------------*/
2542/*--- Stack pointer adjustment ---*/
2543/*------------------------------------------------------------*/
2544
njneccf7c02009-01-19 23:42:45 +00002545#ifdef PERF_FAST_STACK
2546# define MAYBE_USED
2547#else
2548# define MAYBE_USED __attribute__((unused))
2549#endif
2550
sewardj7cf4e6b2008-05-01 20:24:26 +00002551/*--------------- adjustment by 4 bytes ---------------*/
2552
njneccf7c02009-01-19 23:42:45 +00002553MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002554static void VG_REGPARM(2) mc_new_mem_stack_4_w_ECU(Addr new_SP, UInt ecu)
2555{
2556 UInt otag = ecu | MC_OKIND_STACK;
2557 PROF_EVENT(110, "new_mem_stack_4");
2558 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2559 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2560 } else {
2561 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 4, otag );
2562 }
2563}
2564
njneccf7c02009-01-19 23:42:45 +00002565MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002566static void VG_REGPARM(1) mc_new_mem_stack_4(Addr new_SP)
2567{
2568 PROF_EVENT(110, "new_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002569 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002570 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njn1d0825f2006-03-27 11:37:07 +00002571 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002572 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 4 );
njn1d0825f2006-03-27 11:37:07 +00002573 }
2574}
2575
njneccf7c02009-01-19 23:42:45 +00002576MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002577static void VG_REGPARM(1) mc_die_mem_stack_4(Addr new_SP)
2578{
2579 PROF_EVENT(120, "die_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002580 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002581 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002582 } else {
njndbf7ca72006-03-31 11:57:59 +00002583 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-4, 4 );
njn1d0825f2006-03-27 11:37:07 +00002584 }
2585}
2586
sewardj7cf4e6b2008-05-01 20:24:26 +00002587/*--------------- adjustment by 8 bytes ---------------*/
2588
njneccf7c02009-01-19 23:42:45 +00002589MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002590static void VG_REGPARM(2) mc_new_mem_stack_8_w_ECU(Addr new_SP, UInt ecu)
2591{
2592 UInt otag = ecu | MC_OKIND_STACK;
2593 PROF_EVENT(111, "new_mem_stack_8");
2594 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2595 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2596 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2597 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2598 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2599 } else {
2600 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 8, otag );
2601 }
2602}
2603
njneccf7c02009-01-19 23:42:45 +00002604MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002605static void VG_REGPARM(1) mc_new_mem_stack_8(Addr new_SP)
2606{
2607 PROF_EVENT(111, "new_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002608 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002609 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
sewardj05a46732006-10-17 01:28:10 +00002610 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002611 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002612 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002613 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002614 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 8 );
njn1d0825f2006-03-27 11:37:07 +00002615 }
2616}
2617
njneccf7c02009-01-19 23:42:45 +00002618MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002619static void VG_REGPARM(1) mc_die_mem_stack_8(Addr new_SP)
2620{
2621 PROF_EVENT(121, "die_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002622 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002623 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002624 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002625 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
2626 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002627 } else {
njndbf7ca72006-03-31 11:57:59 +00002628 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-8, 8 );
njn1d0825f2006-03-27 11:37:07 +00002629 }
2630}
2631
sewardj7cf4e6b2008-05-01 20:24:26 +00002632/*--------------- adjustment by 12 bytes ---------------*/
2633
njneccf7c02009-01-19 23:42:45 +00002634MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002635static void VG_REGPARM(2) mc_new_mem_stack_12_w_ECU(Addr new_SP, UInt ecu)
2636{
2637 UInt otag = ecu | MC_OKIND_STACK;
2638 PROF_EVENT(112, "new_mem_stack_12");
2639 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2640 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2641 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2642 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2643 /* from previous test we don't have 8-alignment at offset +0,
2644 hence must have 8 alignment at offsets +4/-4. Hence safe to
2645 do 4 at +0 and then 8 at +4/. */
2646 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2647 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2648 } else {
2649 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 12, otag );
2650 }
2651}
2652
njneccf7c02009-01-19 23:42:45 +00002653MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002654static void VG_REGPARM(1) mc_new_mem_stack_12(Addr new_SP)
2655{
2656 PROF_EVENT(112, "new_mem_stack_12");
sewardj05a46732006-10-17 01:28:10 +00002657 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002658 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002659 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002660 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002661 /* from previous test we don't have 8-alignment at offset +0,
2662 hence must have 8 alignment at offsets +4/-4. Hence safe to
2663 do 4 at +0 and then 8 at +4/. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002664 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002665 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002666 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002667 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 12 );
njn1d0825f2006-03-27 11:37:07 +00002668 }
2669}
2670
njneccf7c02009-01-19 23:42:45 +00002671MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002672static void VG_REGPARM(1) mc_die_mem_stack_12(Addr new_SP)
2673{
2674 PROF_EVENT(122, "die_mem_stack_12");
2675 /* Note the -12 in the test */
sewardj43fcfd92006-10-17 23:14:42 +00002676 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP-12 )) {
2677 /* We have 8-alignment at -12, hence ok to do 8 at -12 and 4 at
2678 -4. */
njndbf7ca72006-03-31 11:57:59 +00002679 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2680 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
sewardj05a46732006-10-17 01:28:10 +00002681 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002682 /* We have 4-alignment at +0, but we don't have 8-alignment at
2683 -12. So we must have 8-alignment at -8. Hence do 4 at -12
2684 and then 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002685 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2686 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
njn1d0825f2006-03-27 11:37:07 +00002687 } else {
njndbf7ca72006-03-31 11:57:59 +00002688 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-12, 12 );
njn1d0825f2006-03-27 11:37:07 +00002689 }
2690}
2691
sewardj7cf4e6b2008-05-01 20:24:26 +00002692/*--------------- adjustment by 16 bytes ---------------*/
2693
njneccf7c02009-01-19 23:42:45 +00002694MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002695static void VG_REGPARM(2) mc_new_mem_stack_16_w_ECU(Addr new_SP, UInt ecu)
2696{
2697 UInt otag = ecu | MC_OKIND_STACK;
2698 PROF_EVENT(113, "new_mem_stack_16");
2699 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2700 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
2701 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2702 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2703 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2704 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2705 Hence do 4 at +0, 8 at +4, 4 at +12. */
2706 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2707 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2708 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2709 } else {
2710 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 16, otag );
2711 }
2712}
2713
njneccf7c02009-01-19 23:42:45 +00002714MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002715static void VG_REGPARM(1) mc_new_mem_stack_16(Addr new_SP)
2716{
2717 PROF_EVENT(113, "new_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002718 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002719 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002720 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002721 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002722 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002723 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2724 Hence do 4 at +0, 8 at +4, 4 at +12. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002725 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002726 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
2727 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
njn1d0825f2006-03-27 11:37:07 +00002728 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002729 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 16 );
njn1d0825f2006-03-27 11:37:07 +00002730 }
2731}
2732
njneccf7c02009-01-19 23:42:45 +00002733MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002734static void VG_REGPARM(1) mc_die_mem_stack_16(Addr new_SP)
2735{
2736 PROF_EVENT(123, "die_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002737 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002738 /* Have 8-alignment at +0, hence do 8 at -16 and 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002739 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2740 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002741 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002742 /* 8 alignment must be at -12. Do 4 at -16, 8 at -12, 4 at -4. */
njndbf7ca72006-03-31 11:57:59 +00002743 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2744 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2745 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002746 } else {
njndbf7ca72006-03-31 11:57:59 +00002747 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-16, 16 );
njn1d0825f2006-03-27 11:37:07 +00002748 }
2749}
2750
sewardj7cf4e6b2008-05-01 20:24:26 +00002751/*--------------- adjustment by 32 bytes ---------------*/
2752
njneccf7c02009-01-19 23:42:45 +00002753MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002754static void VG_REGPARM(2) mc_new_mem_stack_32_w_ECU(Addr new_SP, UInt ecu)
2755{
2756 UInt otag = ecu | MC_OKIND_STACK;
2757 PROF_EVENT(114, "new_mem_stack_32");
2758 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2759 /* Straightforward */
2760 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2761 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2762 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2763 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2764 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2765 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2766 +0,+28. */
2767 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2768 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2769 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2770 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+20, otag );
2771 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+28, otag );
2772 } else {
2773 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 32, otag );
2774 }
2775}
2776
njneccf7c02009-01-19 23:42:45 +00002777MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002778static void VG_REGPARM(1) mc_new_mem_stack_32(Addr new_SP)
2779{
2780 PROF_EVENT(114, "new_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002781 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002782 /* Straightforward */
sewardj7cf4e6b2008-05-01 20:24:26 +00002783 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2784 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002785 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2786 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
sewardj05a46732006-10-17 01:28:10 +00002787 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002788 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2789 +0,+28. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002790 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2791 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njndbf7ca72006-03-31 11:57:59 +00002792 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
2793 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+20 );
2794 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+28 );
njn1d0825f2006-03-27 11:37:07 +00002795 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002796 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 32 );
njn1d0825f2006-03-27 11:37:07 +00002797 }
2798}
2799
njneccf7c02009-01-19 23:42:45 +00002800MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002801static void VG_REGPARM(1) mc_die_mem_stack_32(Addr new_SP)
2802{
2803 PROF_EVENT(124, "die_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002804 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002805 /* Straightforward */
njndbf7ca72006-03-31 11:57:59 +00002806 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2807 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2808 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2809 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
sewardj05a46732006-10-17 01:28:10 +00002810 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002811 /* 8 alignment must be at -4 etc. Hence do 8 at -12,-20,-28 and
2812 4 at -32,-4. */
njndbf7ca72006-03-31 11:57:59 +00002813 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2814 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-28 );
2815 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-20 );
2816 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2817 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002818 } else {
njndbf7ca72006-03-31 11:57:59 +00002819 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-32, 32 );
njn1d0825f2006-03-27 11:37:07 +00002820 }
2821}
2822
sewardj7cf4e6b2008-05-01 20:24:26 +00002823/*--------------- adjustment by 112 bytes ---------------*/
2824
njneccf7c02009-01-19 23:42:45 +00002825MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002826static void VG_REGPARM(2) mc_new_mem_stack_112_w_ECU(Addr new_SP, UInt ecu)
2827{
2828 UInt otag = ecu | MC_OKIND_STACK;
2829 PROF_EVENT(115, "new_mem_stack_112");
2830 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2831 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2832 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2833 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2834 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2835 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2836 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2837 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2838 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2839 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2840 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2841 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2842 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2843 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2844 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2845 } else {
2846 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 112, otag );
2847 }
2848}
2849
njneccf7c02009-01-19 23:42:45 +00002850MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002851static void VG_REGPARM(1) mc_new_mem_stack_112(Addr new_SP)
2852{
2853 PROF_EVENT(115, "new_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002854 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002855 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2856 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002857 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2858 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2859 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2860 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2861 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2862 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2863 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2864 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2865 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2866 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2867 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002868 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
njn1d0825f2006-03-27 11:37:07 +00002869 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002870 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 112 );
njn1d0825f2006-03-27 11:37:07 +00002871 }
2872}
2873
njneccf7c02009-01-19 23:42:45 +00002874MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002875static void VG_REGPARM(1) mc_die_mem_stack_112(Addr new_SP)
2876{
2877 PROF_EVENT(125, "die_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002878 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002879 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2880 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2881 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2882 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2883 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2884 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2885 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2886 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2887 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2888 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2889 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2890 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2891 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2892 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002893 } else {
njndbf7ca72006-03-31 11:57:59 +00002894 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-112, 112 );
njn1d0825f2006-03-27 11:37:07 +00002895 }
2896}
2897
sewardj7cf4e6b2008-05-01 20:24:26 +00002898/*--------------- adjustment by 128 bytes ---------------*/
2899
njneccf7c02009-01-19 23:42:45 +00002900MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002901static void VG_REGPARM(2) mc_new_mem_stack_128_w_ECU(Addr new_SP, UInt ecu)
2902{
2903 UInt otag = ecu | MC_OKIND_STACK;
2904 PROF_EVENT(116, "new_mem_stack_128");
2905 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2906 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2907 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2908 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2909 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2910 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2911 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2912 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2913 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2914 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2915 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2916 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2917 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2918 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2919 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2920 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2921 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2922 } else {
2923 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 128, otag );
2924 }
2925}
2926
njneccf7c02009-01-19 23:42:45 +00002927MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002928static void VG_REGPARM(1) mc_new_mem_stack_128(Addr new_SP)
2929{
2930 PROF_EVENT(116, "new_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002931 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002932 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2933 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002934 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2935 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2936 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2937 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2938 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2939 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2940 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2941 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2942 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2943 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2944 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002945 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2946 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2947 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
njn1d0825f2006-03-27 11:37:07 +00002948 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002949 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 128 );
njn1d0825f2006-03-27 11:37:07 +00002950 }
2951}
2952
njneccf7c02009-01-19 23:42:45 +00002953MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00002954static void VG_REGPARM(1) mc_die_mem_stack_128(Addr new_SP)
2955{
2956 PROF_EVENT(126, "die_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002957 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002958 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2959 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2960 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2961 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2962 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2963 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2964 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2965 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2966 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2967 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2968 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2969 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2970 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2971 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2972 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2973 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002974 } else {
njndbf7ca72006-03-31 11:57:59 +00002975 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-128, 128 );
njn1d0825f2006-03-27 11:37:07 +00002976 }
2977}
2978
sewardj7cf4e6b2008-05-01 20:24:26 +00002979/*--------------- adjustment by 144 bytes ---------------*/
2980
njneccf7c02009-01-19 23:42:45 +00002981MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00002982static void VG_REGPARM(2) mc_new_mem_stack_144_w_ECU(Addr new_SP, UInt ecu)
2983{
2984 UInt otag = ecu | MC_OKIND_STACK;
2985 PROF_EVENT(117, "new_mem_stack_144");
2986 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2987 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2988 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2989 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2990 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2991 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2992 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2993 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2994 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2995 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2996 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2997 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2998 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2999 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
3000 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
3001 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
3002 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
3003 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
3004 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
3005 } else {
3006 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 144, otag );
3007 }
3008}
3009
njneccf7c02009-01-19 23:42:45 +00003010MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003011static void VG_REGPARM(1) mc_new_mem_stack_144(Addr new_SP)
3012{
3013 PROF_EVENT(117, "new_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00003014 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003015 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
3016 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00003017 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
3018 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
3019 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
3020 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
3021 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
3022 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
3023 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
3024 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
3025 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
3026 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
3027 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00003028 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
3029 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
3030 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
3031 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
3032 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
njn1d0825f2006-03-27 11:37:07 +00003033 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003034 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 144 );
njn1d0825f2006-03-27 11:37:07 +00003035 }
3036}
3037
njneccf7c02009-01-19 23:42:45 +00003038MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003039static void VG_REGPARM(1) mc_die_mem_stack_144(Addr new_SP)
3040{
3041 PROF_EVENT(127, "die_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00003042 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00003043 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
3044 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
3045 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
3046 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
3047 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
3048 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
3049 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
3050 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
3051 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
3052 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
3053 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
3054 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
3055 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3056 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3057 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3058 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3059 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3060 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003061 } else {
njndbf7ca72006-03-31 11:57:59 +00003062 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-144, 144 );
njn1d0825f2006-03-27 11:37:07 +00003063 }
3064}
3065
sewardj7cf4e6b2008-05-01 20:24:26 +00003066/*--------------- adjustment by 160 bytes ---------------*/
3067
njneccf7c02009-01-19 23:42:45 +00003068MAYBE_USED
sewardj7cf4e6b2008-05-01 20:24:26 +00003069static void VG_REGPARM(2) mc_new_mem_stack_160_w_ECU(Addr new_SP, UInt ecu)
3070{
3071 UInt otag = ecu | MC_OKIND_STACK;
3072 PROF_EVENT(118, "new_mem_stack_160");
3073 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
3074 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
3075 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
3076 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
3077 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
3078 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
3079 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
3080 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
3081 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
3082 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
3083 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
3084 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
3085 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
3086 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
3087 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
3088 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
3089 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
3090 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
3091 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
3092 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+144, otag );
3093 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+152, otag );
3094 } else {
3095 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 160, otag );
3096 }
3097}
3098
njneccf7c02009-01-19 23:42:45 +00003099MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003100static void VG_REGPARM(1) mc_new_mem_stack_160(Addr new_SP)
3101{
3102 PROF_EVENT(118, "new_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003103 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003104 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
3105 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00003106 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
3107 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
3108 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
3109 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
3110 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
3111 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
3112 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
3113 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
3114 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
3115 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
3116 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00003117 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
3118 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
3119 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
3120 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
3121 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
3122 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+144 );
3123 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+152 );
njn1d0825f2006-03-27 11:37:07 +00003124 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003125 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 160 );
njn1d0825f2006-03-27 11:37:07 +00003126 }
3127}
3128
njneccf7c02009-01-19 23:42:45 +00003129MAYBE_USED
njn1d0825f2006-03-27 11:37:07 +00003130static void VG_REGPARM(1) mc_die_mem_stack_160(Addr new_SP)
3131{
3132 PROF_EVENT(128, "die_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00003133 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00003134 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-160);
3135 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-152);
3136 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
3137 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
3138 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
3139 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
3140 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
3141 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
3142 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
3143 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
3144 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
3145 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
3146 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
3147 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
3148 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
3149 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
3150 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
3151 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
3152 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
3153 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00003154 } else {
njndbf7ca72006-03-31 11:57:59 +00003155 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-160, 160 );
njn1d0825f2006-03-27 11:37:07 +00003156 }
3157}
3158
sewardj7cf4e6b2008-05-01 20:24:26 +00003159/*--------------- adjustment by N bytes ---------------*/
3160
3161static void mc_new_mem_stack_w_ECU ( Addr a, SizeT len, UInt ecu )
3162{
3163 UInt otag = ecu | MC_OKIND_STACK;
3164 PROF_EVENT(115, "new_mem_stack_w_otag");
3165 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + a, len, otag );
3166}
3167
njn1d0825f2006-03-27 11:37:07 +00003168static void mc_new_mem_stack ( Addr a, SizeT len )
3169{
3170 PROF_EVENT(115, "new_mem_stack");
sewardj7cf4e6b2008-05-01 20:24:26 +00003171 make_mem_undefined ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003172}
3173
3174static void mc_die_mem_stack ( Addr a, SizeT len )
3175{
3176 PROF_EVENT(125, "die_mem_stack");
njndbf7ca72006-03-31 11:57:59 +00003177 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00003178}
njn9b007f62003-04-07 14:40:25 +00003179
sewardj45d94cc2005-04-20 14:44:11 +00003180
njn1d0825f2006-03-27 11:37:07 +00003181/* The AMD64 ABI says:
3182
3183 "The 128-byte area beyond the location pointed to by %rsp is considered
3184 to be reserved and shall not be modified by signal or interrupt
3185 handlers. Therefore, functions may use this area for temporary data
3186 that is not needed across function calls. In particular, leaf functions
3187 may use this area for their entire stack frame, rather than adjusting
3188 the stack pointer in the prologue and epilogue. This area is known as
3189 red zone [sic]."
3190
3191 So after any call or return we need to mark this redzone as containing
3192 undefined values.
3193
3194 Consider this: we're in function f. f calls g. g moves rsp down
3195 modestly (say 16 bytes) and writes stuff all over the red zone, making it
3196 defined. g returns. f is buggy and reads from parts of the red zone
3197 that it didn't write on. But because g filled that area in, f is going
3198 to be picking up defined V bits and so any errors from reading bits of
3199 the red zone it didn't write, will be missed. The only solution I could
3200 think of was to make the red zone undefined when g returns to f.
3201
3202 This is in accordance with the ABI, which makes it clear the redzone
3203 is volatile across function calls.
3204
3205 The problem occurs the other way round too: f could fill the RZ up
3206 with defined values and g could mistakenly read them. So the RZ
3207 also needs to be nuked on function calls.
3208*/
sewardj7cf4e6b2008-05-01 20:24:26 +00003209
3210
3211/* Here's a simple cache to hold nia -> ECU mappings. It could be
3212 improved so as to have a lower miss rate. */
3213
3214static UWord stats__nia_cache_queries = 0;
3215static UWord stats__nia_cache_misses = 0;
3216
3217typedef
3218 struct { UWord nia0; UWord ecu0; /* nia0 maps to ecu0 */
3219 UWord nia1; UWord ecu1; } /* nia1 maps to ecu1 */
3220 WCacheEnt;
3221
3222#define N_NIA_TO_ECU_CACHE 511
3223
3224static WCacheEnt nia_to_ecu_cache[N_NIA_TO_ECU_CACHE];
3225
3226static void init_nia_to_ecu_cache ( void )
sewardj826ec492005-05-12 18:05:00 +00003227{
sewardj7cf4e6b2008-05-01 20:24:26 +00003228 UWord i;
3229 Addr zero_addr = 0;
3230 ExeContext* zero_ec;
3231 UInt zero_ecu;
3232 /* Fill all the slots with an entry for address zero, and the
3233 relevant otags accordingly. Hence the cache is initially filled
3234 with valid data. */
3235 zero_ec = VG_(make_depth_1_ExeContext_from_Addr)(zero_addr);
3236 tl_assert(zero_ec);
3237 zero_ecu = VG_(get_ECU_from_ExeContext)(zero_ec);
3238 tl_assert(VG_(is_plausible_ECU)(zero_ecu));
3239 for (i = 0; i < N_NIA_TO_ECU_CACHE; i++) {
3240 nia_to_ecu_cache[i].nia0 = zero_addr;
3241 nia_to_ecu_cache[i].ecu0 = zero_ecu;
3242 nia_to_ecu_cache[i].nia1 = zero_addr;
3243 nia_to_ecu_cache[i].ecu1 = zero_ecu;
3244 }
3245}
3246
3247static inline UInt convert_nia_to_ecu ( Addr nia )
3248{
3249 UWord i;
3250 UInt ecu;
3251 ExeContext* ec;
3252
3253 tl_assert( sizeof(nia_to_ecu_cache[0].nia1) == sizeof(nia) );
3254
3255 stats__nia_cache_queries++;
3256 i = nia % N_NIA_TO_ECU_CACHE;
3257 tl_assert(i >= 0 && i < N_NIA_TO_ECU_CACHE);
3258
3259 if (LIKELY( nia_to_ecu_cache[i].nia0 == nia ))
3260 return nia_to_ecu_cache[i].ecu0;
3261
3262 if (LIKELY( nia_to_ecu_cache[i].nia1 == nia )) {
3263# define SWAP(_w1,_w2) { UWord _t = _w1; _w1 = _w2; _w2 = _t; }
3264 SWAP( nia_to_ecu_cache[i].nia0, nia_to_ecu_cache[i].nia1 );
3265 SWAP( nia_to_ecu_cache[i].ecu0, nia_to_ecu_cache[i].ecu1 );
3266# undef SWAP
3267 return nia_to_ecu_cache[i].ecu0;
3268 }
3269
3270 stats__nia_cache_misses++;
3271 ec = VG_(make_depth_1_ExeContext_from_Addr)(nia);
3272 tl_assert(ec);
3273 ecu = VG_(get_ECU_from_ExeContext)(ec);
3274 tl_assert(VG_(is_plausible_ECU)(ecu));
3275
3276 nia_to_ecu_cache[i].nia1 = nia_to_ecu_cache[i].nia0;
3277 nia_to_ecu_cache[i].ecu1 = nia_to_ecu_cache[i].ecu0;
3278
3279 nia_to_ecu_cache[i].nia0 = nia;
3280 nia_to_ecu_cache[i].ecu0 = (UWord)ecu;
3281 return ecu;
3282}
3283
3284
3285/* Note that this serves both the origin-tracking and
3286 no-origin-tracking modes. We assume that calls to it are
3287 sufficiently infrequent that it isn't worth specialising for the
3288 with/without origin-tracking cases. */
3289void MC_(helperc_MAKE_STACK_UNINIT) ( Addr base, UWord len, Addr nia )
3290{
3291 UInt otag;
sewardj826ec492005-05-12 18:05:00 +00003292 tl_assert(sizeof(UWord) == sizeof(SizeT));
sewardj2a3a1a72005-05-12 23:25:43 +00003293 if (0)
barta0b6b2c2008-07-07 06:49:24 +00003294 VG_(printf)("helperc_MAKE_STACK_UNINIT (%#lx,%lu,nia=%#lx)\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00003295 base, len, nia );
3296
3297 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3298 UInt ecu = convert_nia_to_ecu ( nia );
3299 tl_assert(VG_(is_plausible_ECU)(ecu));
3300 otag = ecu | MC_OKIND_STACK;
3301 } else {
3302 tl_assert(nia == 0);
3303 otag = 0;
3304 }
sewardj2a3a1a72005-05-12 23:25:43 +00003305
3306# if 0
3307 /* Really slow version */
sewardj7cf4e6b2008-05-01 20:24:26 +00003308 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003309# endif
3310
3311# if 0
3312 /* Slow(ish) version, which is fairly easily seen to be correct.
3313 */
bart5dd8e6a2008-03-22 08:04:29 +00003314 if (LIKELY( VG_IS_8_ALIGNED(base) && len==128 )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003315 make_aligned_word64_undefined(base + 0, otag);
3316 make_aligned_word64_undefined(base + 8, otag);
3317 make_aligned_word64_undefined(base + 16, otag);
3318 make_aligned_word64_undefined(base + 24, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003319
sewardj7cf4e6b2008-05-01 20:24:26 +00003320 make_aligned_word64_undefined(base + 32, otag);
3321 make_aligned_word64_undefined(base + 40, otag);
3322 make_aligned_word64_undefined(base + 48, otag);
3323 make_aligned_word64_undefined(base + 56, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003324
sewardj7cf4e6b2008-05-01 20:24:26 +00003325 make_aligned_word64_undefined(base + 64, otag);
3326 make_aligned_word64_undefined(base + 72, otag);
3327 make_aligned_word64_undefined(base + 80, otag);
3328 make_aligned_word64_undefined(base + 88, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003329
sewardj7cf4e6b2008-05-01 20:24:26 +00003330 make_aligned_word64_undefined(base + 96, otag);
3331 make_aligned_word64_undefined(base + 104, otag);
3332 make_aligned_word64_undefined(base + 112, otag);
3333 make_aligned_word64_undefined(base + 120, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003334 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003335 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003336 }
3337# endif
3338
3339 /* Idea is: go fast when
3340 * 8-aligned and length is 128
3341 * the sm is available in the main primary map
njn1d0825f2006-03-27 11:37:07 +00003342 * the address range falls entirely with a single secondary map
3343 If all those conditions hold, just update the V+A bits by writing
3344 directly into the vabits array. (If the sm was distinguished, this
3345 will make a copy and then write to it.)
sewardj2a3a1a72005-05-12 23:25:43 +00003346 */
sewardj7cf4e6b2008-05-01 20:24:26 +00003347
bart5dd8e6a2008-03-22 08:04:29 +00003348 if (LIKELY( len == 128 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003349 /* Now we know the address range is suitably sized and aligned. */
3350 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003351 UWord a_hi = (UWord)(base + 128 - 1);
njn1d0825f2006-03-27 11:37:07 +00003352 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003353 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003354 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003355 SecMap* sm = get_secmap_for_writing_low(a_lo);
3356 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2a3a1a72005-05-12 23:25:43 +00003357 /* Now we know that the entire address range falls within a
3358 single secondary map, and that that secondary 'lives' in
3359 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003360 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003361 // Finally, we know that the range is entirely within one secmap.
3362 UWord v_off = SM_OFF(a_lo);
3363 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003364 p[ 0] = VA_BITS16_UNDEFINED;
3365 p[ 1] = VA_BITS16_UNDEFINED;
3366 p[ 2] = VA_BITS16_UNDEFINED;
3367 p[ 3] = VA_BITS16_UNDEFINED;
3368 p[ 4] = VA_BITS16_UNDEFINED;
3369 p[ 5] = VA_BITS16_UNDEFINED;
3370 p[ 6] = VA_BITS16_UNDEFINED;
3371 p[ 7] = VA_BITS16_UNDEFINED;
3372 p[ 8] = VA_BITS16_UNDEFINED;
3373 p[ 9] = VA_BITS16_UNDEFINED;
3374 p[10] = VA_BITS16_UNDEFINED;
3375 p[11] = VA_BITS16_UNDEFINED;
3376 p[12] = VA_BITS16_UNDEFINED;
3377 p[13] = VA_BITS16_UNDEFINED;
3378 p[14] = VA_BITS16_UNDEFINED;
3379 p[15] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003380 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3381 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3382 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3383 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3384 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3385 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3386 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3387 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3388 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3389 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3390 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3391 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3392 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3393 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3394 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3395 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3396 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3397 }
sewardj2a3a1a72005-05-12 23:25:43 +00003398 return;
njn1d0825f2006-03-27 11:37:07 +00003399 }
sewardj2a3a1a72005-05-12 23:25:43 +00003400 }
3401 }
3402
sewardj2e1a6772006-01-18 04:16:27 +00003403 /* 288 bytes (36 ULongs) is the magic value for ELF ppc64. */
bart5dd8e6a2008-03-22 08:04:29 +00003404 if (LIKELY( len == 288 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003405 /* Now we know the address range is suitably sized and aligned. */
3406 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003407 UWord a_hi = (UWord)(base + 288 - 1);
njn1d0825f2006-03-27 11:37:07 +00003408 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003409 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003410 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003411 SecMap* sm = get_secmap_for_writing_low(a_lo);
3412 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2e1a6772006-01-18 04:16:27 +00003413 /* Now we know that the entire address range falls within a
3414 single secondary map, and that that secondary 'lives' in
3415 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003416 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003417 // Finally, we know that the range is entirely within one secmap.
3418 UWord v_off = SM_OFF(a_lo);
3419 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003420 p[ 0] = VA_BITS16_UNDEFINED;
3421 p[ 1] = VA_BITS16_UNDEFINED;
3422 p[ 2] = VA_BITS16_UNDEFINED;
3423 p[ 3] = VA_BITS16_UNDEFINED;
3424 p[ 4] = VA_BITS16_UNDEFINED;
3425 p[ 5] = VA_BITS16_UNDEFINED;
3426 p[ 6] = VA_BITS16_UNDEFINED;
3427 p[ 7] = VA_BITS16_UNDEFINED;
3428 p[ 8] = VA_BITS16_UNDEFINED;
3429 p[ 9] = VA_BITS16_UNDEFINED;
3430 p[10] = VA_BITS16_UNDEFINED;
3431 p[11] = VA_BITS16_UNDEFINED;
3432 p[12] = VA_BITS16_UNDEFINED;
3433 p[13] = VA_BITS16_UNDEFINED;
3434 p[14] = VA_BITS16_UNDEFINED;
3435 p[15] = VA_BITS16_UNDEFINED;
3436 p[16] = VA_BITS16_UNDEFINED;
3437 p[17] = VA_BITS16_UNDEFINED;
3438 p[18] = VA_BITS16_UNDEFINED;
3439 p[19] = VA_BITS16_UNDEFINED;
3440 p[20] = VA_BITS16_UNDEFINED;
3441 p[21] = VA_BITS16_UNDEFINED;
3442 p[22] = VA_BITS16_UNDEFINED;
3443 p[23] = VA_BITS16_UNDEFINED;
3444 p[24] = VA_BITS16_UNDEFINED;
3445 p[25] = VA_BITS16_UNDEFINED;
3446 p[26] = VA_BITS16_UNDEFINED;
3447 p[27] = VA_BITS16_UNDEFINED;
3448 p[28] = VA_BITS16_UNDEFINED;
3449 p[29] = VA_BITS16_UNDEFINED;
3450 p[30] = VA_BITS16_UNDEFINED;
3451 p[31] = VA_BITS16_UNDEFINED;
3452 p[32] = VA_BITS16_UNDEFINED;
3453 p[33] = VA_BITS16_UNDEFINED;
3454 p[34] = VA_BITS16_UNDEFINED;
3455 p[35] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003456 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3457 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3458 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3459 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3460 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3461 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3462 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3463 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3464 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3465 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3466 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3467 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3468 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3469 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3470 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3471 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3472 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3473 set_aligned_word64_Origin_to_undef( base + 8 * 16, otag );
3474 set_aligned_word64_Origin_to_undef( base + 8 * 17, otag );
3475 set_aligned_word64_Origin_to_undef( base + 8 * 18, otag );
3476 set_aligned_word64_Origin_to_undef( base + 8 * 19, otag );
3477 set_aligned_word64_Origin_to_undef( base + 8 * 20, otag );
3478 set_aligned_word64_Origin_to_undef( base + 8 * 21, otag );
3479 set_aligned_word64_Origin_to_undef( base + 8 * 22, otag );
3480 set_aligned_word64_Origin_to_undef( base + 8 * 23, otag );
3481 set_aligned_word64_Origin_to_undef( base + 8 * 24, otag );
3482 set_aligned_word64_Origin_to_undef( base + 8 * 25, otag );
3483 set_aligned_word64_Origin_to_undef( base + 8 * 26, otag );
3484 set_aligned_word64_Origin_to_undef( base + 8 * 27, otag );
3485 set_aligned_word64_Origin_to_undef( base + 8 * 28, otag );
3486 set_aligned_word64_Origin_to_undef( base + 8 * 29, otag );
3487 set_aligned_word64_Origin_to_undef( base + 8 * 30, otag );
3488 set_aligned_word64_Origin_to_undef( base + 8 * 31, otag );
3489 set_aligned_word64_Origin_to_undef( base + 8 * 32, otag );
3490 set_aligned_word64_Origin_to_undef( base + 8 * 33, otag );
3491 set_aligned_word64_Origin_to_undef( base + 8 * 34, otag );
3492 set_aligned_word64_Origin_to_undef( base + 8 * 35, otag );
3493 }
sewardj2e1a6772006-01-18 04:16:27 +00003494 return;
njn1d0825f2006-03-27 11:37:07 +00003495 }
sewardj2e1a6772006-01-18 04:16:27 +00003496 }
3497 }
3498
sewardj2a3a1a72005-05-12 23:25:43 +00003499 /* else fall into slow case */
sewardj7cf4e6b2008-05-01 20:24:26 +00003500 MC_(make_mem_undefined_w_otag)(base, len, otag);
sewardj826ec492005-05-12 18:05:00 +00003501}
3502
3503
nethercote8b76fe52004-11-08 19:20:09 +00003504/*------------------------------------------------------------*/
3505/*--- Checking memory ---*/
3506/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003507
sewardje4ccc012005-05-02 12:53:38 +00003508typedef
3509 enum {
3510 MC_Ok = 5,
3511 MC_AddrErr = 6,
3512 MC_ValueErr = 7
3513 }
3514 MC_ReadResult;
3515
3516
njn25e49d8e72002-09-23 09:36:25 +00003517/* Check permissions for address range. If inadequate permissions
3518 exist, *bad_addr is set to the offending address, so the caller can
3519 know what it is. */
3520
sewardjecf8e102003-07-12 12:11:39 +00003521/* Returns True if [a .. a+len) is not addressible. Otherwise,
3522 returns False, and if bad_addr is non-NULL, sets *bad_addr to
3523 indicate the lowest failing address. Functions below are
3524 similar. */
njndbf7ca72006-03-31 11:57:59 +00003525Bool MC_(check_mem_is_noaccess) ( Addr a, SizeT len, Addr* bad_addr )
sewardjecf8e102003-07-12 12:11:39 +00003526{
nethercote451eae92004-11-02 13:06:32 +00003527 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003528 UWord vabits2;
3529
njndbf7ca72006-03-31 11:57:59 +00003530 PROF_EVENT(60, "check_mem_is_noaccess");
sewardjecf8e102003-07-12 12:11:39 +00003531 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003532 PROF_EVENT(61, "check_mem_is_noaccess(loop)");
njn1d0825f2006-03-27 11:37:07 +00003533 vabits2 = get_vabits2(a);
3534 if (VA_BITS2_NOACCESS != vabits2) {
3535 if (bad_addr != NULL) *bad_addr = a;
sewardjecf8e102003-07-12 12:11:39 +00003536 return False;
3537 }
3538 a++;
3539 }
3540 return True;
3541}
3542
sewardj7cf4e6b2008-05-01 20:24:26 +00003543static Bool is_mem_addressable ( Addr a, SizeT len,
3544 /*OUT*/Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +00003545{
nethercote451eae92004-11-02 13:06:32 +00003546 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003547 UWord vabits2;
3548
njndbf7ca72006-03-31 11:57:59 +00003549 PROF_EVENT(62, "is_mem_addressable");
njn25e49d8e72002-09-23 09:36:25 +00003550 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003551 PROF_EVENT(63, "is_mem_addressable(loop)");
njn1d0825f2006-03-27 11:37:07 +00003552 vabits2 = get_vabits2(a);
3553 if (VA_BITS2_NOACCESS == vabits2) {
njn25e49d8e72002-09-23 09:36:25 +00003554 if (bad_addr != NULL) *bad_addr = a;
3555 return False;
3556 }
3557 a++;
3558 }
3559 return True;
3560}
3561
sewardj7cf4e6b2008-05-01 20:24:26 +00003562static MC_ReadResult is_mem_defined ( Addr a, SizeT len,
3563 /*OUT*/Addr* bad_addr,
3564 /*OUT*/UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003565{
nethercote451eae92004-11-02 13:06:32 +00003566 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003567 UWord vabits2;
njn25e49d8e72002-09-23 09:36:25 +00003568
njndbf7ca72006-03-31 11:57:59 +00003569 PROF_EVENT(64, "is_mem_defined");
3570 DEBUG("is_mem_defined\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003571
3572 if (otag) *otag = 0;
3573 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003574 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003575 PROF_EVENT(65, "is_mem_defined(loop)");
njn1d0825f2006-03-27 11:37:07 +00003576 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003577 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003578 // Error! Nb: Report addressability errors in preference to
3579 // definedness errors. And don't report definedeness errors unless
3580 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003581 if (bad_addr) {
3582 *bad_addr = a;
3583 }
3584 if (VA_BITS2_NOACCESS == vabits2) {
3585 return MC_AddrErr;
3586 }
3587 if (MC_(clo_mc_level) >= 2) {
3588 if (otag && MC_(clo_mc_level) == 3) {
3589 *otag = MC_(helperc_b_load1)( a );
3590 }
3591 return MC_ValueErr;
3592 }
njn25e49d8e72002-09-23 09:36:25 +00003593 }
3594 a++;
3595 }
nethercote8b76fe52004-11-08 19:20:09 +00003596 return MC_Ok;
njn25e49d8e72002-09-23 09:36:25 +00003597}
3598
3599
3600/* Check a zero-terminated ascii string. Tricky -- don't want to
3601 examine the actual bytes, to find the end, until we're sure it is
3602 safe to do so. */
3603
sewardj7cf4e6b2008-05-01 20:24:26 +00003604static Bool mc_is_defined_asciiz ( Addr a, Addr* bad_addr, UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003605{
njn1d0825f2006-03-27 11:37:07 +00003606 UWord vabits2;
3607
njndbf7ca72006-03-31 11:57:59 +00003608 PROF_EVENT(66, "mc_is_defined_asciiz");
3609 DEBUG("mc_is_defined_asciiz\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003610
3611 if (otag) *otag = 0;
3612 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003613 while (True) {
njndbf7ca72006-03-31 11:57:59 +00003614 PROF_EVENT(67, "mc_is_defined_asciiz(loop)");
njn1d0825f2006-03-27 11:37:07 +00003615 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003616 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003617 // Error! Nb: Report addressability errors in preference to
3618 // definedness errors. And don't report definedeness errors unless
3619 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003620 if (bad_addr) {
3621 *bad_addr = a;
3622 }
3623 if (VA_BITS2_NOACCESS == vabits2) {
3624 return MC_AddrErr;
3625 }
3626 if (MC_(clo_mc_level) >= 2) {
3627 if (otag && MC_(clo_mc_level) == 3) {
3628 *otag = MC_(helperc_b_load1)( a );
3629 }
3630 return MC_ValueErr;
3631 }
njn25e49d8e72002-09-23 09:36:25 +00003632 }
3633 /* Ok, a is safe to read. */
njn1d0825f2006-03-27 11:37:07 +00003634 if (* ((UChar*)a) == 0) {
sewardj45d94cc2005-04-20 14:44:11 +00003635 return MC_Ok;
njn1d0825f2006-03-27 11:37:07 +00003636 }
njn25e49d8e72002-09-23 09:36:25 +00003637 a++;
3638 }
3639}
3640
3641
3642/*------------------------------------------------------------*/
3643/*--- Memory event handlers ---*/
3644/*------------------------------------------------------------*/
3645
njn25e49d8e72002-09-23 09:36:25 +00003646static
njndbf7ca72006-03-31 11:57:59 +00003647void check_mem_is_addressable ( CorePart part, ThreadId tid, Char* s,
3648 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003649{
njn25e49d8e72002-09-23 09:36:25 +00003650 Addr bad_addr;
njndbf7ca72006-03-31 11:57:59 +00003651 Bool ok = is_mem_addressable ( base, size, &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003652
njn25e49d8e72002-09-23 09:36:25 +00003653 if (!ok) {
3654 switch (part) {
3655 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003656 MC_(record_memparam_error) ( tid, bad_addr,
3657 /*isAddrErr*/True, s, 0/*otag*/ );
njn25e49d8e72002-09-23 09:36:25 +00003658 break;
3659
njn25e49d8e72002-09-23 09:36:25 +00003660 case Vg_CoreSignal:
njn1dcee092009-02-24 03:07:37 +00003661 MC_(record_core_mem_error)( tid, s );
njn25e49d8e72002-09-23 09:36:25 +00003662 break;
3663
3664 default:
njndbf7ca72006-03-31 11:57:59 +00003665 VG_(tool_panic)("check_mem_is_addressable: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003666 }
3667 }
njn25e49d8e72002-09-23 09:36:25 +00003668}
3669
3670static
njndbf7ca72006-03-31 11:57:59 +00003671void check_mem_is_defined ( CorePart part, ThreadId tid, Char* s,
nethercote451eae92004-11-02 13:06:32 +00003672 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003673{
sewardj7cf4e6b2008-05-01 20:24:26 +00003674 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003675 Addr bad_addr;
sewardj7cf4e6b2008-05-01 20:24:26 +00003676 MC_ReadResult res = is_mem_defined ( base, size, &bad_addr, &otag );
sewardj45f4e7c2005-09-27 19:20:21 +00003677
nethercote8b76fe52004-11-08 19:20:09 +00003678 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003679 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj45f4e7c2005-09-27 19:20:21 +00003680
njn25e49d8e72002-09-23 09:36:25 +00003681 switch (part) {
3682 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003683 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3684 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003685 break;
3686
njnf76d27a2009-05-28 01:53:07 +00003687 case Vg_CoreSysCallArgInMem:
3688 MC_(record_regparam_error) ( tid, s, otag );
3689 break;
3690
njn25e49d8e72002-09-23 09:36:25 +00003691 /* If we're being asked to jump to a silly address, record an error
3692 message before potentially crashing the entire system. */
3693 case Vg_CoreTranslate:
sewardj7ce71662008-05-02 10:33:15 +00003694 MC_(record_jump_error)( tid, bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003695 break;
3696
3697 default:
njndbf7ca72006-03-31 11:57:59 +00003698 VG_(tool_panic)("check_mem_is_defined: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003699 }
3700 }
njn25e49d8e72002-09-23 09:36:25 +00003701}
3702
3703static
njndbf7ca72006-03-31 11:57:59 +00003704void check_mem_is_defined_asciiz ( CorePart part, ThreadId tid,
njn5c004e42002-11-18 11:04:50 +00003705 Char* s, Addr str )
njn25e49d8e72002-09-23 09:36:25 +00003706{
nethercote8b76fe52004-11-08 19:20:09 +00003707 MC_ReadResult res;
njn5ab96ac2005-05-08 02:59:50 +00003708 Addr bad_addr = 0; // shut GCC up
sewardj7cf4e6b2008-05-01 20:24:26 +00003709 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003710
njnca82cc02004-11-22 17:18:48 +00003711 tl_assert(part == Vg_CoreSysCall);
sewardj7cf4e6b2008-05-01 20:24:26 +00003712 res = mc_is_defined_asciiz ( (Addr)str, &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00003713 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003714 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj7ce71662008-05-02 10:33:15 +00003715 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3716 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003717 }
njn25e49d8e72002-09-23 09:36:25 +00003718}
3719
sewardj6f95e7e2010-01-27 10:28:00 +00003720/* Handling of mmap and mprotect is not as simple as it seems.
3721
3722 The underlying semantics are that memory obtained from mmap is
3723 always initialised, but may be inaccessible. And changes to the
3724 protection of memory do not change its contents and hence not its
3725 definedness state. Problem is we can't model
3726 inaccessible-but-with-some-definedness state; once we mark memory
3727 as inaccessible we lose all info about definedness, and so can't
3728 restore that if it is later made accessible again.
3729
3730 One obvious thing to do is this:
3731
3732 mmap/mprotect NONE -> noaccess
3733 mmap/mprotect other -> defined
3734
3735 The problem case here is: taking accessible memory, writing
3736 uninitialised data to it, mprotecting it NONE and later mprotecting
3737 it back to some accessible state causes the undefinedness to be
3738 lost.
3739
3740 A better proposal is:
3741
3742 (1) mmap NONE -> make noaccess
3743 (2) mmap other -> make defined
3744
3745 (3) mprotect NONE -> # no change
3746 (4) mprotect other -> change any "noaccess" to "defined"
3747
3748 (2) is OK because memory newly obtained from mmap really is defined
3749 (zeroed out by the kernel -- doing anything else would
3750 constitute a massive security hole.)
3751
3752 (1) is OK because the only way to make the memory usable is via
3753 (4), in which case we also wind up correctly marking it all as
3754 defined.
3755
3756 (3) is the weak case. We choose not to change memory state.
3757 (presumably the range is in some mixture of "defined" and
3758 "undefined", viz, accessible but with arbitrary V bits). Doing
3759 nothing means we retain the V bits, so that if the memory is
3760 later mprotected "other", the V bits remain unchanged, so there
3761 can be no false negatives. The bad effect is that if there's
3762 an access in the area, then MC cannot warn; but at least we'll
3763 get a SEGV to show, so it's better than nothing.
3764
3765 Consider the sequence (3) followed by (4). Any memory that was
3766 "defined" or "undefined" previously retains its state (as
3767 required). Any memory that was "noaccess" before can only have
3768 been made that way by (1), and so it's OK to change it to
3769 "defined".
3770
3771 See https://bugs.kde.org/show_bug.cgi?id=205541
3772 and https://bugs.kde.org/show_bug.cgi?id=210268
3773*/
njn25e49d8e72002-09-23 09:36:25 +00003774static
njnf76d27a2009-05-28 01:53:07 +00003775void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
3776 ULong di_handle )
3777{
sewardj6f95e7e2010-01-27 10:28:00 +00003778 if (rr || ww || xx) {
3779 /* (2) mmap/mprotect other -> defined */
njnf76d27a2009-05-28 01:53:07 +00003780 MC_(make_mem_defined)(a, len);
sewardj6f95e7e2010-01-27 10:28:00 +00003781 } else {
3782 /* (1) mmap/mprotect NONE -> noaccess */
njnf76d27a2009-05-28 01:53:07 +00003783 MC_(make_mem_noaccess)(a, len);
sewardj6f95e7e2010-01-27 10:28:00 +00003784 }
njnf76d27a2009-05-28 01:53:07 +00003785}
3786
3787static
sewardj6f95e7e2010-01-27 10:28:00 +00003788void mc_new_mem_mprotect ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
3789{
3790 if (rr || ww || xx) {
3791 /* (4) mprotect other -> change any "noaccess" to "defined" */
3792 make_mem_defined_if_noaccess(a, len);
3793 } else {
3794 /* (3) mprotect NONE -> # no change */
3795 /* do nothing */
3796 }
3797}
3798
3799
3800static
sewardj9c606bd2008-09-18 18:12:50 +00003801void mc_new_mem_startup( Addr a, SizeT len,
3802 Bool rr, Bool ww, Bool xx, ULong di_handle )
njn25e49d8e72002-09-23 09:36:25 +00003803{
njnba7b4582006-09-21 15:59:30 +00003804 // Because code is defined, initialised variables get put in the data
3805 // segment and are defined, and uninitialised variables get put in the
3806 // bss segment and are auto-zeroed (and so defined).
3807 //
3808 // It's possible that there will be padding between global variables.
3809 // This will also be auto-zeroed, and marked as defined by Memcheck. If
3810 // a program uses it, Memcheck will not complain. This is arguably a
3811 // false negative, but it's a grey area -- the behaviour is defined (the
3812 // padding is zeroed) but it's probably not what the user intended. And
3813 // we can't avoid it.
njnf76d27a2009-05-28 01:53:07 +00003814 //
3815 // Note: we generally ignore RWX permissions, because we can't track them
3816 // without requiring more than one A bit which would slow things down a
3817 // lot. But on Darwin the 0th page is mapped but !R and !W and !X.
3818 // So we mark any such pages as "unaddressable".
barta0b6b2c2008-07-07 06:49:24 +00003819 DEBUG("mc_new_mem_startup(%#lx, %llu, rr=%u, ww=%u, xx=%u)\n",
njndbf7ca72006-03-31 11:57:59 +00003820 a, (ULong)len, rr, ww, xx);
njnf76d27a2009-05-28 01:53:07 +00003821 mc_new_mem_mmap(a, len, rr, ww, xx, di_handle);
njn25e49d8e72002-09-23 09:36:25 +00003822}
3823
njncf45fd42004-11-24 16:30:22 +00003824static
3825void mc_post_mem_write(CorePart part, ThreadId tid, Addr a, SizeT len)
3826{
njndbf7ca72006-03-31 11:57:59 +00003827 MC_(make_mem_defined)(a, len);
njncf45fd42004-11-24 16:30:22 +00003828}
njn25e49d8e72002-09-23 09:36:25 +00003829
sewardj45d94cc2005-04-20 14:44:11 +00003830
njn25e49d8e72002-09-23 09:36:25 +00003831/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00003832/*--- Register event handlers ---*/
3833/*------------------------------------------------------------*/
3834
sewardj7cf4e6b2008-05-01 20:24:26 +00003835/* Try and get a nonzero origin for the guest state section of thread
3836 tid characterised by (offset,size). Return 0 if nothing to show
3837 for it. */
3838static UInt mb_get_origin_for_guest_offset ( ThreadId tid,
3839 Int offset, SizeT size )
3840{
3841 Int sh2off;
3842 UChar area[6];
3843 UInt otag;
3844 sh2off = MC_(get_otrack_shadow_offset)( offset, size );
3845 if (sh2off == -1)
3846 return 0; /* This piece of guest state is not tracked */
3847 tl_assert(sh2off >= 0);
3848 tl_assert(0 == (sh2off % 4));
3849 area[0] = 0x31;
3850 area[5] = 0x27;
3851 VG_(get_shadow_regs_area)( tid, &area[1], 2/*shadowno*/,sh2off,4 );
3852 tl_assert(area[0] == 0x31);
3853 tl_assert(area[5] == 0x27);
3854 otag = *(UInt*)&area[1];
3855 return otag;
3856}
3857
3858
sewardj45d94cc2005-04-20 14:44:11 +00003859/* When some chunk of guest state is written, mark the corresponding
3860 shadow area as valid. This is used to initialise arbitrarily large
sewardj62eae5f2006-01-17 01:58:24 +00003861 chunks of guest state, hence the _SIZE value, which has to be as
3862 big as the biggest guest state.
sewardj45d94cc2005-04-20 14:44:11 +00003863*/
3864static void mc_post_reg_write ( CorePart part, ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003865 PtrdiffT offset, SizeT size)
njnd3040452003-05-19 15:04:06 +00003866{
sewardj05a46732006-10-17 01:28:10 +00003867# define MAX_REG_WRITE_SIZE 1408
cerion21082042005-12-06 19:07:08 +00003868 UChar area[MAX_REG_WRITE_SIZE];
3869 tl_assert(size <= MAX_REG_WRITE_SIZE);
njn1d0825f2006-03-27 11:37:07 +00003870 VG_(memset)(area, V_BITS8_DEFINED, size);
sewardj7cf4e6b2008-05-01 20:24:26 +00003871 VG_(set_shadow_regs_area)( tid, 1/*shadowNo*/,offset,size, area );
cerion21082042005-12-06 19:07:08 +00003872# undef MAX_REG_WRITE_SIZE
njnd3040452003-05-19 15:04:06 +00003873}
3874
sewardj45d94cc2005-04-20 14:44:11 +00003875static
3876void mc_post_reg_write_clientcall ( ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00003877 PtrdiffT offset, SizeT size, Addr f)
njnd3040452003-05-19 15:04:06 +00003878{
njncf45fd42004-11-24 16:30:22 +00003879 mc_post_reg_write(/*dummy*/0, tid, offset, size);
njnd3040452003-05-19 15:04:06 +00003880}
3881
sewardj45d94cc2005-04-20 14:44:11 +00003882/* Look at the definedness of the guest's shadow state for
3883 [offset, offset+len). If any part of that is undefined, record
3884 a parameter error.
3885*/
3886static void mc_pre_reg_read ( CorePart part, ThreadId tid, Char* s,
njnc4431bf2009-01-15 21:29:24 +00003887 PtrdiffT offset, SizeT size)
nethercote8b76fe52004-11-08 19:20:09 +00003888{
sewardj45d94cc2005-04-20 14:44:11 +00003889 Int i;
3890 Bool bad;
sewardj7cf4e6b2008-05-01 20:24:26 +00003891 UInt otag;
sewardj45d94cc2005-04-20 14:44:11 +00003892
3893 UChar area[16];
3894 tl_assert(size <= 16);
3895
sewardj7cf4e6b2008-05-01 20:24:26 +00003896 VG_(get_shadow_regs_area)( tid, area, 1/*shadowNo*/,offset,size );
sewardj45d94cc2005-04-20 14:44:11 +00003897
3898 bad = False;
3899 for (i = 0; i < size; i++) {
njn1d0825f2006-03-27 11:37:07 +00003900 if (area[i] != V_BITS8_DEFINED) {
sewardj2c27f702005-05-03 18:19:05 +00003901 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00003902 break;
3903 }
nethercote8b76fe52004-11-08 19:20:09 +00003904 }
3905
sewardj7cf4e6b2008-05-01 20:24:26 +00003906 if (!bad)
3907 return;
3908
3909 /* We've found some undefinedness. See if we can also find an
3910 origin for it. */
3911 otag = mb_get_origin_for_guest_offset( tid, offset, size );
sewardj7ce71662008-05-02 10:33:15 +00003912 MC_(record_regparam_error) ( tid, s, otag );
nethercote8b76fe52004-11-08 19:20:09 +00003913}
njnd3040452003-05-19 15:04:06 +00003914
njn25e49d8e72002-09-23 09:36:25 +00003915
sewardj6cf40ff2005-04-20 22:31:26 +00003916/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00003917/*--- Functions called directly from generated code: ---*/
3918/*--- Load/store handlers. ---*/
sewardj6cf40ff2005-04-20 22:31:26 +00003919/*------------------------------------------------------------*/
3920
njn1d0825f2006-03-27 11:37:07 +00003921/* Types: LOADV32, LOADV16, LOADV8 are:
sewardj6cf40ff2005-04-20 22:31:26 +00003922 UWord fn ( Addr a )
3923 so they return 32-bits on 32-bit machines and 64-bits on
3924 64-bit machines. Addr has the same size as a host word.
3925
njn1d0825f2006-03-27 11:37:07 +00003926 LOADV64 is always ULong fn ( Addr a )
sewardj6cf40ff2005-04-20 22:31:26 +00003927
njn1d0825f2006-03-27 11:37:07 +00003928 Similarly for STOREV8, STOREV16, STOREV32, the supplied vbits
3929 are a UWord, and for STOREV64 they are a ULong.
sewardj6cf40ff2005-04-20 22:31:26 +00003930*/
3931
sewardj7244e712008-05-02 12:35:48 +00003932/* If any part of '_a' indicated by the mask is 1, either '_a' is not
3933 naturally '_sz/8'-aligned, or it exceeds the range covered by the
3934 primary map. This is all very tricky (and important!), so let's
3935 work through the maths by hand (below), *and* assert for these
3936 values at startup. */
3937#define MASK(_szInBytes) \
3938 ( ~((0x10000UL-(_szInBytes)) | ((N_PRIMARY_MAP-1) << 16)) )
3939
3940/* MASK only exists so as to define this macro. */
3941#define UNALIGNED_OR_HIGH(_a,_szInBits) \
3942 ((_a) & MASK((_szInBits>>3)))
3943
3944/* On a 32-bit machine:
3945
3946 N_PRIMARY_BITS == 16, so
3947 N_PRIMARY_MAP == 0x10000, so
3948 N_PRIMARY_MAP-1 == 0xFFFF, so
3949 (N_PRIMARY_MAP-1) << 16 == 0xFFFF0000, and so
3950
3951 MASK(1) = ~ ( (0x10000 - 1) | 0xFFFF0000 )
3952 = ~ ( 0xFFFF | 0xFFFF0000 )
3953 = ~ 0xFFFF'FFFF
3954 = 0
3955
3956 MASK(2) = ~ ( (0x10000 - 2) | 0xFFFF0000 )
3957 = ~ ( 0xFFFE | 0xFFFF0000 )
3958 = ~ 0xFFFF'FFFE
3959 = 1
3960
3961 MASK(4) = ~ ( (0x10000 - 4) | 0xFFFF0000 )
3962 = ~ ( 0xFFFC | 0xFFFF0000 )
3963 = ~ 0xFFFF'FFFC
3964 = 3
3965
3966 MASK(8) = ~ ( (0x10000 - 8) | 0xFFFF0000 )
3967 = ~ ( 0xFFF8 | 0xFFFF0000 )
3968 = ~ 0xFFFF'FFF8
3969 = 7
3970
3971 Hence in the 32-bit case, "a & MASK(1/2/4/8)" is a nonzero value
3972 precisely when a is not 1/2/4/8-bytes aligned. And obviously, for
3973 the 1-byte alignment case, it is always a zero value, since MASK(1)
3974 is zero. All as expected.
3975
3976 On a 64-bit machine, it's more complex, since we're testing
3977 simultaneously for misalignment and for the address being at or
3978 above 32G:
3979
3980 N_PRIMARY_BITS == 19, so
3981 N_PRIMARY_MAP == 0x80000, so
3982 N_PRIMARY_MAP-1 == 0x7FFFF, so
3983 (N_PRIMARY_MAP-1) << 16 == 0x7FFFF'0000, and so
3984
3985 MASK(1) = ~ ( (0x10000 - 1) | 0x7FFFF'0000 )
3986 = ~ ( 0xFFFF | 0x7FFFF'0000 )
3987 = ~ 0x7FFFF'FFFF
3988 = 0xFFFF'FFF8'0000'0000
3989
3990 MASK(2) = ~ ( (0x10000 - 2) | 0x7FFFF'0000 )
3991 = ~ ( 0xFFFE | 0x7FFFF'0000 )
3992 = ~ 0x7FFFF'FFFE
3993 = 0xFFFF'FFF8'0000'0001
3994
3995 MASK(4) = ~ ( (0x10000 - 4) | 0x7FFFF'0000 )
3996 = ~ ( 0xFFFC | 0x7FFFF'0000 )
3997 = ~ 0x7FFFF'FFFC
3998 = 0xFFFF'FFF8'0000'0003
3999
4000 MASK(8) = ~ ( (0x10000 - 8) | 0x7FFFF'0000 )
4001 = ~ ( 0xFFF8 | 0x7FFFF'0000 )
4002 = ~ 0x7FFFF'FFF8
4003 = 0xFFFF'FFF8'0000'0007
4004*/
njn1d0825f2006-03-27 11:37:07 +00004005
4006
sewardj95448072004-11-22 20:19:51 +00004007/* ------------------------ Size = 8 ------------------------ */
4008
njn1d0825f2006-03-27 11:37:07 +00004009static INLINE
4010ULong mc_LOADV64 ( Addr a, Bool isBigEndian )
4011{
njn1d0825f2006-03-27 11:37:07 +00004012 PROF_EVENT(200, "mc_LOADV64");
4013
4014#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004015 return mc_LOADVn_slow( a, 64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004016#else
njneccf7c02009-01-19 23:42:45 +00004017 {
4018 UWord sm_off16, vabits16;
4019 SecMap* sm;
sewardjf9d81612005-04-23 23:25:49 +00004020
njneccf7c02009-01-19 23:42:45 +00004021 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
4022 PROF_EVENT(201, "mc_LOADV64-slow1");
4023 return (ULong)mc_LOADVn_slow( a, 64, isBigEndian );
4024 }
njn1d0825f2006-03-27 11:37:07 +00004025
njneccf7c02009-01-19 23:42:45 +00004026 sm = get_secmap_for_reading_low(a);
4027 sm_off16 = SM_OFF_16(a);
4028 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
4029
4030 // Handle common case quickly: a is suitably aligned, is mapped, and
4031 // addressible.
4032 // Convert V bits from compact memory form to expanded register form.
4033 if (LIKELY(vabits16 == VA_BITS16_DEFINED)) {
4034 return V_BITS64_DEFINED;
4035 } else if (LIKELY(vabits16 == VA_BITS16_UNDEFINED)) {
4036 return V_BITS64_UNDEFINED;
4037 } else {
4038 /* Slow case: the 8 bytes are not all-defined or all-undefined. */
4039 PROF_EVENT(202, "mc_LOADV64-slow2");
4040 return mc_LOADVn_slow( a, 64, isBigEndian );
4041 }
njn1d0825f2006-03-27 11:37:07 +00004042 }
4043#endif
4044}
4045
4046VG_REGPARM(1) ULong MC_(helperc_LOADV64be) ( Addr a )
4047{
4048 return mc_LOADV64(a, True);
4049}
4050VG_REGPARM(1) ULong MC_(helperc_LOADV64le) ( Addr a )
4051{
4052 return mc_LOADV64(a, False);
4053}
sewardjf9d81612005-04-23 23:25:49 +00004054
sewardjf9d81612005-04-23 23:25:49 +00004055
njn1d0825f2006-03-27 11:37:07 +00004056static INLINE
njn4cf530b2006-04-06 13:33:48 +00004057void mc_STOREV64 ( Addr a, ULong vbits64, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004058{
njn1d0825f2006-03-27 11:37:07 +00004059 PROF_EVENT(210, "mc_STOREV64");
4060
4061#ifndef PERF_FAST_STOREV
4062 // XXX: this slow case seems to be marginally faster than the fast case!
4063 // Investigate further.
njn4cf530b2006-04-06 13:33:48 +00004064 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004065#else
njn1d0825f2006-03-27 11:37:07 +00004066 {
njneccf7c02009-01-19 23:42:45 +00004067 UWord sm_off16, vabits16;
4068 SecMap* sm;
4069
4070 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
4071 PROF_EVENT(211, "mc_STOREV64-slow1");
4072 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
4073 return;
4074 }
4075
4076 sm = get_secmap_for_reading_low(a);
4077 sm_off16 = SM_OFF_16(a);
4078 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
4079
4080 if (LIKELY( !is_distinguished_sm(sm) &&
4081 (VA_BITS16_DEFINED == vabits16 ||
4082 VA_BITS16_UNDEFINED == vabits16) ))
4083 {
4084 /* Handle common case quickly: a is suitably aligned, */
4085 /* is mapped, and is addressible. */
4086 // Convert full V-bits in register to compact 2-bit form.
4087 if (V_BITS64_DEFINED == vbits64) {
4088 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
4089 } else if (V_BITS64_UNDEFINED == vbits64) {
4090 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
4091 } else {
4092 /* Slow but general case -- writing partially defined bytes. */
4093 PROF_EVENT(212, "mc_STOREV64-slow2");
4094 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
4095 }
njn1d0825f2006-03-27 11:37:07 +00004096 } else {
njneccf7c02009-01-19 23:42:45 +00004097 /* Slow but general case. */
4098 PROF_EVENT(213, "mc_STOREV64-slow3");
njn4cf530b2006-04-06 13:33:48 +00004099 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004100 }
njn1d0825f2006-03-27 11:37:07 +00004101 }
4102#endif
4103}
4104
njn4cf530b2006-04-06 13:33:48 +00004105VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00004106{
njn4cf530b2006-04-06 13:33:48 +00004107 mc_STOREV64(a, vbits64, True);
njn1d0825f2006-03-27 11:37:07 +00004108}
njn4cf530b2006-04-06 13:33:48 +00004109VG_REGPARM(1) void MC_(helperc_STOREV64le) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00004110{
njn4cf530b2006-04-06 13:33:48 +00004111 mc_STOREV64(a, vbits64, False);
njn1d0825f2006-03-27 11:37:07 +00004112}
sewardj95448072004-11-22 20:19:51 +00004113
sewardj95448072004-11-22 20:19:51 +00004114
4115/* ------------------------ Size = 4 ------------------------ */
4116
njn1d0825f2006-03-27 11:37:07 +00004117static INLINE
4118UWord mc_LOADV32 ( Addr a, Bool isBigEndian )
4119{
njn1d0825f2006-03-27 11:37:07 +00004120 PROF_EVENT(220, "mc_LOADV32");
4121
4122#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004123 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004124#else
njneccf7c02009-01-19 23:42:45 +00004125 {
4126 UWord sm_off, vabits8;
4127 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004128
njneccf7c02009-01-19 23:42:45 +00004129 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
4130 PROF_EVENT(221, "mc_LOADV32-slow1");
4131 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
4132 }
njn1d0825f2006-03-27 11:37:07 +00004133
njneccf7c02009-01-19 23:42:45 +00004134 sm = get_secmap_for_reading_low(a);
4135 sm_off = SM_OFF(a);
4136 vabits8 = sm->vabits8[sm_off];
4137
4138 // Handle common case quickly: a is suitably aligned, is mapped, and the
4139 // entire word32 it lives in is addressible.
4140 // Convert V bits from compact memory form to expanded register form.
4141 // For 64-bit platforms, set the high 32 bits of retval to 1 (undefined).
4142 // Almost certainly not necessary, but be paranoid.
4143 if (LIKELY(vabits8 == VA_BITS8_DEFINED)) {
4144 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
4145 } else if (LIKELY(vabits8 == VA_BITS8_UNDEFINED)) {
4146 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
4147 } else {
4148 /* Slow case: the 4 bytes are not all-defined or all-undefined. */
4149 PROF_EVENT(222, "mc_LOADV32-slow2");
4150 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
4151 }
njn1d0825f2006-03-27 11:37:07 +00004152 }
4153#endif
4154}
4155
4156VG_REGPARM(1) UWord MC_(helperc_LOADV32be) ( Addr a )
4157{
4158 return mc_LOADV32(a, True);
4159}
4160VG_REGPARM(1) UWord MC_(helperc_LOADV32le) ( Addr a )
4161{
4162 return mc_LOADV32(a, False);
4163}
sewardjc1a2cda2005-04-21 17:34:00 +00004164
sewardjc1a2cda2005-04-21 17:34:00 +00004165
njn1d0825f2006-03-27 11:37:07 +00004166static INLINE
njn4cf530b2006-04-06 13:33:48 +00004167void mc_STOREV32 ( Addr a, UWord vbits32, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004168{
njn1d0825f2006-03-27 11:37:07 +00004169 PROF_EVENT(230, "mc_STOREV32");
4170
4171#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004172 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004173#else
njneccf7c02009-01-19 23:42:45 +00004174 {
4175 UWord sm_off, vabits8;
4176 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004177
njneccf7c02009-01-19 23:42:45 +00004178 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
4179 PROF_EVENT(231, "mc_STOREV32-slow1");
4180 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004181 return;
njneccf7c02009-01-19 23:42:45 +00004182 }
4183
4184 sm = get_secmap_for_reading_low(a);
4185 sm_off = SM_OFF(a);
4186 vabits8 = sm->vabits8[sm_off];
4187
4188 // Cleverness: sometimes we don't have to write the shadow memory at
4189 // all, if we can tell that what we want to write is the same as what is
4190 // already there. The 64/16/8 bit cases also have cleverness at this
4191 // point, but it works a little differently to the code below.
4192 if (V_BITS32_DEFINED == vbits32) {
4193 if (vabits8 == (UInt)VA_BITS8_DEFINED) {
4194 return;
4195 } else if (!is_distinguished_sm(sm) && VA_BITS8_UNDEFINED == vabits8) {
4196 sm->vabits8[sm_off] = (UInt)VA_BITS8_DEFINED;
4197 } else {
4198 // not defined/undefined, or distinguished and changing state
4199 PROF_EVENT(232, "mc_STOREV32-slow2");
4200 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
4201 }
4202 } else if (V_BITS32_UNDEFINED == vbits32) {
4203 if (vabits8 == (UInt)VA_BITS8_UNDEFINED) {
4204 return;
4205 } else if (!is_distinguished_sm(sm) && VA_BITS8_DEFINED == vabits8) {
4206 sm->vabits8[sm_off] = (UInt)VA_BITS8_UNDEFINED;
4207 } else {
4208 // not defined/undefined, or distinguished and changing state
4209 PROF_EVENT(233, "mc_STOREV32-slow3");
4210 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
4211 }
njn1d0825f2006-03-27 11:37:07 +00004212 } else {
njneccf7c02009-01-19 23:42:45 +00004213 // Partially defined word
4214 PROF_EVENT(234, "mc_STOREV32-slow4");
njn4cf530b2006-04-06 13:33:48 +00004215 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004216 }
njn1d0825f2006-03-27 11:37:07 +00004217 }
njn1d0825f2006-03-27 11:37:07 +00004218#endif
4219}
4220
njn4cf530b2006-04-06 13:33:48 +00004221VG_REGPARM(2) void MC_(helperc_STOREV32be) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004222{
njn4cf530b2006-04-06 13:33:48 +00004223 mc_STOREV32(a, vbits32, True);
njn1d0825f2006-03-27 11:37:07 +00004224}
njn4cf530b2006-04-06 13:33:48 +00004225VG_REGPARM(2) void MC_(helperc_STOREV32le) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00004226{
njn4cf530b2006-04-06 13:33:48 +00004227 mc_STOREV32(a, vbits32, False);
njn1d0825f2006-03-27 11:37:07 +00004228}
njn25e49d8e72002-09-23 09:36:25 +00004229
njn25e49d8e72002-09-23 09:36:25 +00004230
sewardj95448072004-11-22 20:19:51 +00004231/* ------------------------ Size = 2 ------------------------ */
4232
njn1d0825f2006-03-27 11:37:07 +00004233static INLINE
4234UWord mc_LOADV16 ( Addr a, Bool isBigEndian )
4235{
njn1d0825f2006-03-27 11:37:07 +00004236 PROF_EVENT(240, "mc_LOADV16");
4237
4238#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004239 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004240#else
njneccf7c02009-01-19 23:42:45 +00004241 {
4242 UWord sm_off, vabits8;
4243 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004244
njneccf7c02009-01-19 23:42:45 +00004245 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
4246 PROF_EVENT(241, "mc_LOADV16-slow1");
njn45e81252006-03-28 12:35:08 +00004247 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004248 }
njneccf7c02009-01-19 23:42:45 +00004249
4250 sm = get_secmap_for_reading_low(a);
4251 sm_off = SM_OFF(a);
4252 vabits8 = sm->vabits8[sm_off];
4253 // Handle common case quickly: a is suitably aligned, is mapped, and is
4254 // addressible.
4255 // Convert V bits from compact memory form to expanded register form
4256 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS16_DEFINED; }
4257 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS16_UNDEFINED; }
4258 else {
4259 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
4260 // the two sub-bytes.
4261 UChar vabits4 = extract_vabits4_from_vabits8(a, vabits8);
4262 if (vabits4 == VA_BITS4_DEFINED ) { return V_BITS16_DEFINED; }
4263 else if (vabits4 == VA_BITS4_UNDEFINED) { return V_BITS16_UNDEFINED; }
4264 else {
4265 /* Slow case: the two bytes are not all-defined or all-undefined. */
4266 PROF_EVENT(242, "mc_LOADV16-slow2");
4267 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
4268 }
4269 }
njn1d0825f2006-03-27 11:37:07 +00004270 }
4271#endif
4272}
4273
4274VG_REGPARM(1) UWord MC_(helperc_LOADV16be) ( Addr a )
4275{
4276 return mc_LOADV16(a, True);
4277}
4278VG_REGPARM(1) UWord MC_(helperc_LOADV16le) ( Addr a )
4279{
4280 return mc_LOADV16(a, False);
4281}
sewardjc1a2cda2005-04-21 17:34:00 +00004282
sewardjc1a2cda2005-04-21 17:34:00 +00004283
njn1d0825f2006-03-27 11:37:07 +00004284static INLINE
njn4cf530b2006-04-06 13:33:48 +00004285void mc_STOREV16 ( Addr a, UWord vbits16, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00004286{
njn1d0825f2006-03-27 11:37:07 +00004287 PROF_EVENT(250, "mc_STOREV16");
4288
4289#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004290 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004291#else
njn1d0825f2006-03-27 11:37:07 +00004292 {
njneccf7c02009-01-19 23:42:45 +00004293 UWord sm_off, vabits8;
4294 SecMap* sm;
4295
4296 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
4297 PROF_EVENT(251, "mc_STOREV16-slow1");
4298 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
4299 return;
4300 }
4301
4302 sm = get_secmap_for_reading_low(a);
4303 sm_off = SM_OFF(a);
4304 vabits8 = sm->vabits8[sm_off];
4305 if (LIKELY( !is_distinguished_sm(sm) &&
4306 (VA_BITS8_DEFINED == vabits8 ||
4307 VA_BITS8_UNDEFINED == vabits8) ))
4308 {
4309 /* Handle common case quickly: a is suitably aligned, */
4310 /* is mapped, and is addressible. */
4311 // Convert full V-bits in register to compact 2-bit form.
4312 if (V_BITS16_DEFINED == vbits16) {
4313 insert_vabits4_into_vabits8( a, VA_BITS4_DEFINED ,
4314 &(sm->vabits8[sm_off]) );
4315 } else if (V_BITS16_UNDEFINED == vbits16) {
4316 insert_vabits4_into_vabits8( a, VA_BITS4_UNDEFINED,
4317 &(sm->vabits8[sm_off]) );
4318 } else {
4319 /* Slow but general case -- writing partially defined bytes. */
4320 PROF_EVENT(252, "mc_STOREV16-slow2");
4321 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
4322 }
njn1d0825f2006-03-27 11:37:07 +00004323 } else {
njneccf7c02009-01-19 23:42:45 +00004324 /* Slow but general case. */
4325 PROF_EVENT(253, "mc_STOREV16-slow3");
njn4cf530b2006-04-06 13:33:48 +00004326 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00004327 }
njn1d0825f2006-03-27 11:37:07 +00004328 }
4329#endif
4330}
njn25e49d8e72002-09-23 09:36:25 +00004331
njn4cf530b2006-04-06 13:33:48 +00004332VG_REGPARM(2) void MC_(helperc_STOREV16be) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004333{
njn4cf530b2006-04-06 13:33:48 +00004334 mc_STOREV16(a, vbits16, True);
njn1d0825f2006-03-27 11:37:07 +00004335}
njn4cf530b2006-04-06 13:33:48 +00004336VG_REGPARM(2) void MC_(helperc_STOREV16le) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00004337{
njn4cf530b2006-04-06 13:33:48 +00004338 mc_STOREV16(a, vbits16, False);
njn1d0825f2006-03-27 11:37:07 +00004339}
sewardj5d28efc2005-04-21 22:16:29 +00004340
njn25e49d8e72002-09-23 09:36:25 +00004341
sewardj95448072004-11-22 20:19:51 +00004342/* ------------------------ Size = 1 ------------------------ */
sewardj8cf88b72005-07-08 01:29:33 +00004343/* Note: endianness is irrelevant for size == 1 */
sewardj95448072004-11-22 20:19:51 +00004344
njnaf839f52005-06-23 03:27:57 +00004345VG_REGPARM(1)
njn1d0825f2006-03-27 11:37:07 +00004346UWord MC_(helperc_LOADV8) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00004347{
njn1d0825f2006-03-27 11:37:07 +00004348 PROF_EVENT(260, "mc_LOADV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004349
njn1d0825f2006-03-27 11:37:07 +00004350#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00004351 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004352#else
njneccf7c02009-01-19 23:42:45 +00004353 {
4354 UWord sm_off, vabits8;
4355 SecMap* sm;
sewardjc1a2cda2005-04-21 17:34:00 +00004356
njneccf7c02009-01-19 23:42:45 +00004357 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
4358 PROF_EVENT(261, "mc_LOADV8-slow1");
njn45e81252006-03-28 12:35:08 +00004359 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004360 }
njneccf7c02009-01-19 23:42:45 +00004361
4362 sm = get_secmap_for_reading_low(a);
4363 sm_off = SM_OFF(a);
4364 vabits8 = sm->vabits8[sm_off];
4365 // Convert V bits from compact memory form to expanded register form
4366 // Handle common case quickly: a is mapped, and the entire
4367 // word32 it lives in is addressible.
4368 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS8_DEFINED; }
4369 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS8_UNDEFINED; }
4370 else {
4371 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
4372 // the single byte.
4373 UChar vabits2 = extract_vabits2_from_vabits8(a, vabits8);
4374 if (vabits2 == VA_BITS2_DEFINED ) { return V_BITS8_DEFINED; }
4375 else if (vabits2 == VA_BITS2_UNDEFINED) { return V_BITS8_UNDEFINED; }
4376 else {
4377 /* Slow case: the byte is not all-defined or all-undefined. */
4378 PROF_EVENT(262, "mc_LOADV8-slow2");
4379 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
4380 }
4381 }
sewardjc1a2cda2005-04-21 17:34:00 +00004382 }
njn1d0825f2006-03-27 11:37:07 +00004383#endif
njn25e49d8e72002-09-23 09:36:25 +00004384}
4385
sewardjc1a2cda2005-04-21 17:34:00 +00004386
njnaf839f52005-06-23 03:27:57 +00004387VG_REGPARM(2)
njn4cf530b2006-04-06 13:33:48 +00004388void MC_(helperc_STOREV8) ( Addr a, UWord vbits8 )
njn25e49d8e72002-09-23 09:36:25 +00004389{
njn1d0825f2006-03-27 11:37:07 +00004390 PROF_EVENT(270, "mc_STOREV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004391
njn1d0825f2006-03-27 11:37:07 +00004392#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004393 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004394#else
njn1d0825f2006-03-27 11:37:07 +00004395 {
njneccf7c02009-01-19 23:42:45 +00004396 UWord sm_off, vabits8;
4397 SecMap* sm;
4398
4399 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
4400 PROF_EVENT(271, "mc_STOREV8-slow1");
4401 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
4402 return;
4403 }
4404
4405 sm = get_secmap_for_reading_low(a);
4406 sm_off = SM_OFF(a);
4407 vabits8 = sm->vabits8[sm_off];
4408 if (LIKELY
4409 ( !is_distinguished_sm(sm) &&
4410 ( (VA_BITS8_DEFINED == vabits8 || VA_BITS8_UNDEFINED == vabits8)
4411 || (VA_BITS2_NOACCESS != extract_vabits2_from_vabits8(a, vabits8))
4412 )
4413 )
4414 )
4415 {
4416 /* Handle common case quickly: a is mapped, the entire word32 it
4417 lives in is addressible. */
4418 // Convert full V-bits in register to compact 2-bit form.
4419 if (V_BITS8_DEFINED == vbits8) {
4420 insert_vabits2_into_vabits8( a, VA_BITS2_DEFINED,
4421 &(sm->vabits8[sm_off]) );
4422 } else if (V_BITS8_UNDEFINED == vbits8) {
4423 insert_vabits2_into_vabits8( a, VA_BITS2_UNDEFINED,
4424 &(sm->vabits8[sm_off]) );
4425 } else {
4426 /* Slow but general case -- writing partially defined bytes. */
4427 PROF_EVENT(272, "mc_STOREV8-slow2");
4428 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
4429 }
njn1d0825f2006-03-27 11:37:07 +00004430 } else {
njneccf7c02009-01-19 23:42:45 +00004431 /* Slow but general case. */
4432 PROF_EVENT(273, "mc_STOREV8-slow3");
njn4cf530b2006-04-06 13:33:48 +00004433 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004434 }
sewardjc1a2cda2005-04-21 17:34:00 +00004435 }
njn1d0825f2006-03-27 11:37:07 +00004436#endif
njn25e49d8e72002-09-23 09:36:25 +00004437}
4438
4439
sewardjc859fbf2005-04-22 21:10:28 +00004440/*------------------------------------------------------------*/
4441/*--- Functions called directly from generated code: ---*/
4442/*--- Value-check failure handlers. ---*/
4443/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004444
sewardj7cf4e6b2008-05-01 20:24:26 +00004445/* Call these ones when an origin is available ... */
4446VG_REGPARM(1)
4447void MC_(helperc_value_check0_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004448 MC_(record_cond_error) ( VG_(get_running_tid)(), (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004449}
4450
sewardj7cf4e6b2008-05-01 20:24:26 +00004451VG_REGPARM(1)
4452void MC_(helperc_value_check1_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004453 MC_(record_value_error) ( VG_(get_running_tid)(), 1, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004454}
4455
sewardj7cf4e6b2008-05-01 20:24:26 +00004456VG_REGPARM(1)
4457void MC_(helperc_value_check4_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004458 MC_(record_value_error) ( VG_(get_running_tid)(), 4, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004459}
4460
sewardj7cf4e6b2008-05-01 20:24:26 +00004461VG_REGPARM(1)
4462void MC_(helperc_value_check8_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004463 MC_(record_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin );
sewardj11bcc4e2005-04-23 22:38:38 +00004464}
4465
sewardj7cf4e6b2008-05-01 20:24:26 +00004466VG_REGPARM(2)
4467void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004468 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin );
sewardj7cf4e6b2008-05-01 20:24:26 +00004469}
4470
4471/* ... and these when an origin isn't available. */
4472
4473VG_REGPARM(0)
4474void MC_(helperc_value_check0_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004475 MC_(record_cond_error) ( VG_(get_running_tid)(), 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004476}
4477
4478VG_REGPARM(0)
4479void MC_(helperc_value_check1_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004480 MC_(record_value_error) ( VG_(get_running_tid)(), 1, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004481}
4482
4483VG_REGPARM(0)
4484void MC_(helperc_value_check4_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004485 MC_(record_value_error) ( VG_(get_running_tid)(), 4, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004486}
4487
4488VG_REGPARM(0)
4489void MC_(helperc_value_check8_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004490 MC_(record_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004491}
4492
4493VG_REGPARM(1)
4494void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) {
sewardj7ce71662008-05-02 10:33:15 +00004495 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ );
sewardj95448072004-11-22 20:19:51 +00004496}
4497
njn25e49d8e72002-09-23 09:36:25 +00004498
sewardjc2c12c22006-03-08 13:20:09 +00004499/*------------------------------------------------------------*/
4500/*--- Metadata get/set functions, for client requests. ---*/
4501/*------------------------------------------------------------*/
4502
njn1d0825f2006-03-27 11:37:07 +00004503// Nb: this expands the V+A bits out into register-form V bits, even though
4504// they're in memory. This is for backward compatibility, and because it's
4505// probably what the user wants.
4506
4507/* Copy Vbits from/to address 'a'. Returns: 1 == OK, 2 == alignment
sewardjc2c12c22006-03-08 13:20:09 +00004508 error [no longer used], 3 == addressing error. */
njn718d3b12006-12-16 00:54:12 +00004509/* Nb: We used to issue various definedness/addressability errors from here,
4510 but we took them out because they ranged from not-very-helpful to
4511 downright annoying, and they complicated the error data structures. */
sewardjc2c12c22006-03-08 13:20:09 +00004512static Int mc_get_or_set_vbits_for_client (
njn1d0825f2006-03-27 11:37:07 +00004513 Addr a,
4514 Addr vbits,
4515 SizeT szB,
sewardjc2c12c22006-03-08 13:20:09 +00004516 Bool setting /* True <=> set vbits, False <=> get vbits */
4517)
4518{
sewardjc2c12c22006-03-08 13:20:09 +00004519 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00004520 Bool ok;
4521 UChar vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004522
njn1d0825f2006-03-27 11:37:07 +00004523 /* Check that arrays are addressible before doing any getting/setting. */
4524 for (i = 0; i < szB; i++) {
njn718d3b12006-12-16 00:54:12 +00004525 if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
4526 VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
njn1d0825f2006-03-27 11:37:07 +00004527 return 3;
sewardjc2c12c22006-03-08 13:20:09 +00004528 }
4529 }
njn1d0825f2006-03-27 11:37:07 +00004530
sewardjc2c12c22006-03-08 13:20:09 +00004531 /* Do the copy */
4532 if (setting) {
njn1d0825f2006-03-27 11:37:07 +00004533 /* setting */
4534 for (i = 0; i < szB; i++) {
4535 ok = set_vbits8(a + i, ((UChar*)vbits)[i]);
4536 tl_assert(ok);
sewardjc2c12c22006-03-08 13:20:09 +00004537 }
4538 } else {
4539 /* getting */
njn1d0825f2006-03-27 11:37:07 +00004540 for (i = 0; i < szB; i++) {
4541 ok = get_vbits8(a + i, &vbits8);
4542 tl_assert(ok);
njn1d0825f2006-03-27 11:37:07 +00004543 ((UChar*)vbits)[i] = vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004544 }
4545 // The bytes in vbits[] have now been set, so mark them as such.
njndbf7ca72006-03-31 11:57:59 +00004546 MC_(make_mem_defined)(vbits, szB);
njn1d0825f2006-03-27 11:37:07 +00004547 }
sewardjc2c12c22006-03-08 13:20:09 +00004548
4549 return 1;
4550}
sewardj05fe85e2005-04-27 22:46:36 +00004551
4552
4553/*------------------------------------------------------------*/
4554/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
4555/*------------------------------------------------------------*/
4556
4557/* For the memory leak detector, say whether an entire 64k chunk of
4558 address space is possibly in use, or not. If in doubt return
4559 True.
4560*/
njn8225cc02009-03-09 22:52:24 +00004561Bool MC_(is_within_valid_secondary) ( Addr a )
sewardj05fe85e2005-04-27 22:46:36 +00004562{
4563 SecMap* sm = maybe_get_secmap_for ( a );
sewardj05a46732006-10-17 01:28:10 +00004564 if (sm == NULL || sm == &sm_distinguished[SM_DIST_NOACCESS]
sewardj7ce71662008-05-02 10:33:15 +00004565 || MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004566 /* Definitely not in use. */
4567 return False;
4568 } else {
4569 return True;
4570 }
4571}
4572
4573
4574/* For the memory leak detector, say whether or not a given word
4575 address is to be regarded as valid. */
njn8225cc02009-03-09 22:52:24 +00004576Bool MC_(is_valid_aligned_word) ( Addr a )
sewardj05fe85e2005-04-27 22:46:36 +00004577{
4578 tl_assert(sizeof(UWord) == 4 || sizeof(UWord) == 8);
njn8225cc02009-03-09 22:52:24 +00004579 tl_assert(VG_IS_WORD_ALIGNED(a));
sewardj7cf4e6b2008-05-01 20:24:26 +00004580 if (is_mem_defined( a, sizeof(UWord), NULL, NULL) == MC_Ok
sewardj7ce71662008-05-02 10:33:15 +00004581 && !MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004582 return True;
4583 } else {
4584 return False;
4585 }
4586}
sewardja4495682002-10-21 07:29:59 +00004587
4588
sewardjc859fbf2005-04-22 21:10:28 +00004589/*------------------------------------------------------------*/
4590/*--- Initialisation ---*/
4591/*------------------------------------------------------------*/
4592
4593static void init_shadow_memory ( void )
4594{
4595 Int i;
4596 SecMap* sm;
4597
njn1d0825f2006-03-27 11:37:07 +00004598 tl_assert(V_BIT_UNDEFINED == 1);
4599 tl_assert(V_BIT_DEFINED == 0);
4600 tl_assert(V_BITS8_UNDEFINED == 0xFF);
4601 tl_assert(V_BITS8_DEFINED == 0);
4602
sewardjc859fbf2005-04-22 21:10:28 +00004603 /* Build the 3 distinguished secondaries */
sewardjc859fbf2005-04-22 21:10:28 +00004604 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004605 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_NOACCESS;
sewardjc859fbf2005-04-22 21:10:28 +00004606
njndbf7ca72006-03-31 11:57:59 +00004607 sm = &sm_distinguished[SM_DIST_UNDEFINED];
4608 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_UNDEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004609
njndbf7ca72006-03-31 11:57:59 +00004610 sm = &sm_distinguished[SM_DIST_DEFINED];
4611 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_DEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004612
4613 /* Set up the primary map. */
4614 /* These entries gradually get overwritten as the used address
4615 space expands. */
4616 for (i = 0; i < N_PRIMARY_MAP; i++)
4617 primary_map[i] = &sm_distinguished[SM_DIST_NOACCESS];
4618
sewardj05a46732006-10-17 01:28:10 +00004619 /* Auxiliary primary maps */
4620 init_auxmap_L1_L2();
4621
sewardjc859fbf2005-04-22 21:10:28 +00004622 /* auxmap_size = auxmap_used = 0;
4623 no ... these are statically initialised */
njn1d0825f2006-03-27 11:37:07 +00004624
4625 /* Secondary V bit table */
4626 secVBitTable = createSecVBitTable();
sewardjc859fbf2005-04-22 21:10:28 +00004627}
4628
4629
4630/*------------------------------------------------------------*/
4631/*--- Sanity check machinery (permanently engaged) ---*/
4632/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004633
njn51d827b2005-05-09 01:02:08 +00004634static Bool mc_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004635{
sewardj23eb2fd2005-04-22 16:29:19 +00004636 n_sanity_cheap++;
sewardjc1a2cda2005-04-21 17:34:00 +00004637 PROF_EVENT(490, "cheap_sanity_check");
sewardj7cf4e6b2008-05-01 20:24:26 +00004638 /* Check for sane operating level */
4639 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4640 return False;
4641 /* nothing else useful we can rapidly check */
jseward9800fd32004-01-04 23:08:04 +00004642 return True;
njn25e49d8e72002-09-23 09:36:25 +00004643}
4644
njn51d827b2005-05-09 01:02:08 +00004645static Bool mc_expensive_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004646{
sewardj05a46732006-10-17 01:28:10 +00004647 Int i;
4648 Word n_secmaps_found;
sewardj45d94cc2005-04-20 14:44:11 +00004649 SecMap* sm;
sewardj05a46732006-10-17 01:28:10 +00004650 HChar* errmsg;
sewardj23eb2fd2005-04-22 16:29:19 +00004651 Bool bad = False;
njn25e49d8e72002-09-23 09:36:25 +00004652
sewardj05a46732006-10-17 01:28:10 +00004653 if (0) VG_(printf)("expensive sanity check\n");
4654 if (0) return True;
4655
sewardj23eb2fd2005-04-22 16:29:19 +00004656 n_sanity_expensive++;
sewardjc1a2cda2005-04-21 17:34:00 +00004657 PROF_EVENT(491, "expensive_sanity_check");
4658
sewardj7cf4e6b2008-05-01 20:24:26 +00004659 /* Check for sane operating level */
4660 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4661 return False;
4662
njn1d0825f2006-03-27 11:37:07 +00004663 /* Check that the 3 distinguished SMs are still as they should be. */
njn25e49d8e72002-09-23 09:36:25 +00004664
njndbf7ca72006-03-31 11:57:59 +00004665 /* Check noaccess DSM. */
sewardj45d94cc2005-04-20 14:44:11 +00004666 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004667 for (i = 0; i < SM_CHUNKS; i++)
4668 if (sm->vabits8[i] != VA_BITS8_NOACCESS)
sewardj23eb2fd2005-04-22 16:29:19 +00004669 bad = True;
njn25e49d8e72002-09-23 09:36:25 +00004670
njndbf7ca72006-03-31 11:57:59 +00004671 /* Check undefined DSM. */
4672 sm = &sm_distinguished[SM_DIST_UNDEFINED];
njn1d0825f2006-03-27 11:37:07 +00004673 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004674 if (sm->vabits8[i] != VA_BITS8_UNDEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004675 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004676
njndbf7ca72006-03-31 11:57:59 +00004677 /* Check defined DSM. */
4678 sm = &sm_distinguished[SM_DIST_DEFINED];
njn1d0825f2006-03-27 11:37:07 +00004679 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004680 if (sm->vabits8[i] != VA_BITS8_DEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004681 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004682
sewardj23eb2fd2005-04-22 16:29:19 +00004683 if (bad) {
4684 VG_(printf)("memcheck expensive sanity: "
4685 "distinguished_secondaries have changed\n");
4686 return False;
4687 }
4688
njn1d0825f2006-03-27 11:37:07 +00004689 /* If we're not checking for undefined value errors, the secondary V bit
4690 * table should be empty. */
sewardj7cf4e6b2008-05-01 20:24:26 +00004691 if (MC_(clo_mc_level) == 1) {
njne2a9ad32007-09-17 05:30:48 +00004692 if (0 != VG_(OSetGen_Size)(secVBitTable))
njn1d0825f2006-03-27 11:37:07 +00004693 return False;
4694 }
4695
sewardj05a46732006-10-17 01:28:10 +00004696 /* check the auxiliary maps, very thoroughly */
4697 n_secmaps_found = 0;
4698 errmsg = check_auxmap_L1_L2_sanity( &n_secmaps_found );
4699 if (errmsg) {
4700 VG_(printf)("memcheck expensive sanity, auxmaps:\n\t%s", errmsg);
sewardj23eb2fd2005-04-22 16:29:19 +00004701 return False;
4702 }
4703
sewardj05a46732006-10-17 01:28:10 +00004704 /* n_secmaps_found is now the number referred to by the auxiliary
4705 primary map. Now add on the ones referred to by the main
4706 primary map. */
sewardj23eb2fd2005-04-22 16:29:19 +00004707 for (i = 0; i < N_PRIMARY_MAP; i++) {
sewardj05a46732006-10-17 01:28:10 +00004708 if (primary_map[i] == NULL) {
sewardj23eb2fd2005-04-22 16:29:19 +00004709 bad = True;
4710 } else {
sewardj05a46732006-10-17 01:28:10 +00004711 if (!is_distinguished_sm(primary_map[i]))
sewardj23eb2fd2005-04-22 16:29:19 +00004712 n_secmaps_found++;
4713 }
4714 }
4715
sewardj05a46732006-10-17 01:28:10 +00004716 /* check that the number of secmaps issued matches the number that
4717 are reachable (iow, no secmap leaks) */
njn1d0825f2006-03-27 11:37:07 +00004718 if (n_secmaps_found != (n_issued_SMs - n_deissued_SMs))
sewardj23eb2fd2005-04-22 16:29:19 +00004719 bad = True;
4720
4721 if (bad) {
4722 VG_(printf)("memcheck expensive sanity: "
4723 "apparent secmap leakage\n");
4724 return False;
4725 }
4726
sewardj23eb2fd2005-04-22 16:29:19 +00004727 if (bad) {
4728 VG_(printf)("memcheck expensive sanity: "
4729 "auxmap covers wrong address space\n");
4730 return False;
4731 }
4732
4733 /* there is only one pointer to each secmap (expensive) */
njn25e49d8e72002-09-23 09:36:25 +00004734
4735 return True;
4736}
sewardj45d94cc2005-04-20 14:44:11 +00004737
njn25e49d8e72002-09-23 09:36:25 +00004738/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00004739/*--- Command line args ---*/
njn25e49d8e72002-09-23 09:36:25 +00004740/*------------------------------------------------------------*/
4741
njn1d0825f2006-03-27 11:37:07 +00004742Bool MC_(clo_partial_loads_ok) = False;
sewardja88fb0b2010-10-13 21:19:54 +00004743Long MC_(clo_freelist_vol) = 20*1000*1000LL;
njn1d0825f2006-03-27 11:37:07 +00004744LeakCheckMode MC_(clo_leak_check) = LC_Summary;
njn5daa2d32009-07-10 08:16:29 +00004745VgRes MC_(clo_leak_resolution) = Vg_HighRes;
njn1d0825f2006-03-27 11:37:07 +00004746Bool MC_(clo_show_reachable) = False;
bart3cedf572010-08-26 10:56:27 +00004747Bool MC_(clo_show_possibly_lost) = True;
njn1d0825f2006-03-27 11:37:07 +00004748Bool MC_(clo_workaround_gcc296_bugs) = False;
sewardjeb0fa932007-11-30 21:41:40 +00004749Int MC_(clo_malloc_fill) = -1;
4750Int MC_(clo_free_fill) = -1;
sewardj7cf4e6b2008-05-01 20:24:26 +00004751Int MC_(clo_mc_level) = 2;
njn1d0825f2006-03-27 11:37:07 +00004752
4753static Bool mc_process_cmd_line_options(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00004754{
njn83df0b62009-02-25 01:01:05 +00004755 Char* tmp_str;
njn83df0b62009-02-25 01:01:05 +00004756
sewardj7cf4e6b2008-05-01 20:24:26 +00004757 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
4758
4759 /* Set MC_(clo_mc_level):
4760 1 = A bit tracking only
4761 2 = A and V bit tracking, but no V bit origins
4762 3 = A and V bit tracking, and V bit origins
4763
4764 Do this by inspecting --undef-value-errors= and
4765 --track-origins=. Reject the case --undef-value-errors=no
4766 --track-origins=yes as meaningless.
4767 */
4768 if (0 == VG_(strcmp)(arg, "--undef-value-errors=no")) {
njn83df0b62009-02-25 01:01:05 +00004769 if (MC_(clo_mc_level) == 3) {
njnb1cc5d62010-07-06 04:05:23 +00004770 goto bad_level;
njn83df0b62009-02-25 01:01:05 +00004771 } else {
4772 MC_(clo_mc_level) = 1;
4773 return True;
4774 }
sewardj7cf4e6b2008-05-01 20:24:26 +00004775 }
4776 if (0 == VG_(strcmp)(arg, "--undef-value-errors=yes")) {
4777 if (MC_(clo_mc_level) == 1)
4778 MC_(clo_mc_level) = 2;
4779 return True;
4780 }
4781 if (0 == VG_(strcmp)(arg, "--track-origins=no")) {
4782 if (MC_(clo_mc_level) == 3)
4783 MC_(clo_mc_level) = 2;
4784 return True;
4785 }
4786 if (0 == VG_(strcmp)(arg, "--track-origins=yes")) {
njn83df0b62009-02-25 01:01:05 +00004787 if (MC_(clo_mc_level) == 1) {
njnb1cc5d62010-07-06 04:05:23 +00004788 goto bad_level;
njn83df0b62009-02-25 01:01:05 +00004789 } else {
4790 MC_(clo_mc_level) = 3;
4791 return True;
4792 }
sewardj7cf4e6b2008-05-01 20:24:26 +00004793 }
4794
njn83df0b62009-02-25 01:01:05 +00004795 if VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok)) {}
4796 else if VG_BOOL_CLO(arg, "--show-reachable", MC_(clo_show_reachable)) {}
bart3cedf572010-08-26 10:56:27 +00004797 else if VG_BOOL_CLO(arg, "--show-possibly-lost",
4798 MC_(clo_show_possibly_lost)) {}
njn83df0b62009-02-25 01:01:05 +00004799 else if VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",
4800 MC_(clo_workaround_gcc296_bugs)) {}
njn1d0825f2006-03-27 11:37:07 +00004801
njn83df0b62009-02-25 01:01:05 +00004802 else if VG_BINT_CLO(arg, "--freelist-vol", MC_(clo_freelist_vol),
4803 0, 10*1000*1000*1000LL) {}
njn1d0825f2006-03-27 11:37:07 +00004804
njn83df0b62009-02-25 01:01:05 +00004805 else if VG_XACT_CLO(arg, "--leak-check=no",
4806 MC_(clo_leak_check), LC_Off) {}
4807 else if VG_XACT_CLO(arg, "--leak-check=summary",
4808 MC_(clo_leak_check), LC_Summary) {}
4809 else if VG_XACT_CLO(arg, "--leak-check=yes",
4810 MC_(clo_leak_check), LC_Full) {}
4811 else if VG_XACT_CLO(arg, "--leak-check=full",
4812 MC_(clo_leak_check), LC_Full) {}
njn1d0825f2006-03-27 11:37:07 +00004813
njn83df0b62009-02-25 01:01:05 +00004814 else if VG_XACT_CLO(arg, "--leak-resolution=low",
4815 MC_(clo_leak_resolution), Vg_LowRes) {}
4816 else if VG_XACT_CLO(arg, "--leak-resolution=med",
4817 MC_(clo_leak_resolution), Vg_MedRes) {}
4818 else if VG_XACT_CLO(arg, "--leak-resolution=high",
4819 MC_(clo_leak_resolution), Vg_HighRes) {}
njn1d0825f2006-03-27 11:37:07 +00004820
njn83df0b62009-02-25 01:01:05 +00004821 else if VG_STR_CLO(arg, "--ignore-ranges", tmp_str) {
4822 Int i;
4823 Bool ok = parse_ignore_ranges(tmp_str);
sewardj05a46732006-10-17 01:28:10 +00004824 if (!ok)
4825 return False;
4826 tl_assert(ignoreRanges.used >= 0);
4827 tl_assert(ignoreRanges.used < M_IGNORE_RANGES);
4828 for (i = 0; i < ignoreRanges.used; i++) {
4829 Addr s = ignoreRanges.start[i];
4830 Addr e = ignoreRanges.end[i];
4831 Addr limit = 0x4000000; /* 64M - entirely arbitrary limit */
4832 if (e <= s) {
4833 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004834 "ERROR: --ignore-ranges: end <= start in range:\n");
sewardj05a46732006-10-17 01:28:10 +00004835 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004836 " 0x%lx-0x%lx\n", s, e);
sewardj05a46732006-10-17 01:28:10 +00004837 return False;
4838 }
4839 if (e - s > limit) {
4840 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004841 "ERROR: --ignore-ranges: suspiciously large range:\n");
sewardj05a46732006-10-17 01:28:10 +00004842 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004843 " 0x%lx-0x%lx (size %ld)\n", s, e, (UWord)(e-s));
sewardj05a46732006-10-17 01:28:10 +00004844 return False;
4845 }
4846 }
4847 }
4848
njn83df0b62009-02-25 01:01:05 +00004849 else if VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00,0xFF) {}
4850 else if VG_BHEX_CLO(arg, "--free-fill", MC_(clo_free_fill), 0x00,0xFF) {}
sewardjeb0fa932007-11-30 21:41:40 +00004851
njn1d0825f2006-03-27 11:37:07 +00004852 else
4853 return VG_(replacement_malloc_process_cmd_line_option)(arg);
4854
4855 return True;
njnb1cc5d62010-07-06 04:05:23 +00004856
4857
4858 bad_level:
4859 VG_(fmsg_bad_option)(arg,
4860 "--track-origins=yes has no effect when --undef-value-errors=no.\n");
njn25e49d8e72002-09-23 09:36:25 +00004861}
4862
njn51d827b2005-05-09 01:02:08 +00004863static void mc_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00004864{
njn1d0825f2006-03-27 11:37:07 +00004865 VG_(printf)(
4866" --leak-check=no|summary|full search for memory leaks at exit? [summary]\n"
njn5daa2d32009-07-10 08:16:29 +00004867" --leak-resolution=low|med|high differentiation of leak stack traces [high]\n"
njn1d0825f2006-03-27 11:37:07 +00004868" --show-reachable=no|yes show reachable blocks in leak check? [no]\n"
bart3cedf572010-08-26 10:56:27 +00004869" --show-possibly-lost=no|yes show possibly lost blocks in leak check?\n"
4870" [yes]\n"
njn1d0825f2006-03-27 11:37:07 +00004871" --undef-value-errors=no|yes check for undefined value errors [yes]\n"
sewardj7cf4e6b2008-05-01 20:24:26 +00004872" --track-origins=no|yes show origins of undefined values? [no]\n"
njn1d0825f2006-03-27 11:37:07 +00004873" --partial-loads-ok=no|yes too hard to explain here; see manual [no]\n"
sewardja88fb0b2010-10-13 21:19:54 +00004874" --freelist-vol=<number> volume of freed blocks queue [20000000]\n"
njn1d0825f2006-03-27 11:37:07 +00004875" --workaround-gcc296-bugs=no|yes self explanatory [no]\n"
sewardj05a46732006-10-17 01:28:10 +00004876" --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS] assume given addresses are OK\n"
sewardjeb0fa932007-11-30 21:41:40 +00004877" --malloc-fill=<hexnumber> fill malloc'd areas with given value\n"
4878" --free-fill=<hexnumber> fill free'd areas with given value\n"
njn1d0825f2006-03-27 11:37:07 +00004879 );
njn3e884182003-04-15 13:03:23 +00004880}
4881
njn51d827b2005-05-09 01:02:08 +00004882static void mc_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00004883{
njn97db7612009-08-04 02:32:55 +00004884 VG_(printf)(
4885" (none)\n"
4886 );
njn25e49d8e72002-09-23 09:36:25 +00004887}
4888
sewardjf3418c02005-11-08 14:10:24 +00004889
nethercote8b76fe52004-11-08 19:20:09 +00004890/*------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00004891/*--- Client blocks ---*/
nethercote8b76fe52004-11-08 19:20:09 +00004892/*------------------------------------------------------------*/
4893
4894/* Client block management:
4895
4896 This is managed as an expanding array of client block descriptors.
4897 Indices of live descriptors are issued to the client, so it can ask
4898 to free them later. Therefore we cannot slide live entries down
4899 over dead ones. Instead we must use free/inuse flags and scan for
4900 an empty slot at allocation time. This in turn means allocation is
4901 relatively expensive, so we hope this does not happen too often.
nethercote8b76fe52004-11-08 19:20:09 +00004902
sewardjedc75ab2005-03-15 23:30:32 +00004903 An unused block has start == size == 0
4904*/
nethercote8b76fe52004-11-08 19:20:09 +00004905
sewardj7ce71662008-05-02 10:33:15 +00004906/* type CGenBlock is defined in mc_include.h */
nethercote8b76fe52004-11-08 19:20:09 +00004907
4908/* This subsystem is self-initialising. */
sewardj56adc352008-05-02 11:25:17 +00004909static UWord cgb_size = 0;
4910static UWord cgb_used = 0;
njn695c16e2005-03-27 03:40:28 +00004911static CGenBlock* cgbs = NULL;
nethercote8b76fe52004-11-08 19:20:09 +00004912
4913/* Stats for this subsystem. */
sewardj56adc352008-05-02 11:25:17 +00004914static ULong cgb_used_MAX = 0; /* Max in use. */
4915static ULong cgb_allocs = 0; /* Number of allocs. */
4916static ULong cgb_discards = 0; /* Number of discards. */
4917static ULong cgb_search = 0; /* Number of searches. */
nethercote8b76fe52004-11-08 19:20:09 +00004918
4919
sewardj7ce71662008-05-02 10:33:15 +00004920/* Get access to the client block array. */
4921void MC_(get_ClientBlock_array)( /*OUT*/CGenBlock** blocks,
4922 /*OUT*/UWord* nBlocks )
4923{
4924 *blocks = cgbs;
4925 *nBlocks = cgb_used;
4926}
4927
4928
nethercote8b76fe52004-11-08 19:20:09 +00004929static
njn695c16e2005-03-27 03:40:28 +00004930Int alloc_client_block ( void )
nethercote8b76fe52004-11-08 19:20:09 +00004931{
sewardj56adc352008-05-02 11:25:17 +00004932 UWord i, sz_new;
nethercote8b76fe52004-11-08 19:20:09 +00004933 CGenBlock* cgbs_new;
4934
njn695c16e2005-03-27 03:40:28 +00004935 cgb_allocs++;
nethercote8b76fe52004-11-08 19:20:09 +00004936
njn695c16e2005-03-27 03:40:28 +00004937 for (i = 0; i < cgb_used; i++) {
4938 cgb_search++;
4939 if (cgbs[i].start == 0 && cgbs[i].size == 0)
nethercote8b76fe52004-11-08 19:20:09 +00004940 return i;
4941 }
4942
4943 /* Not found. Try to allocate one at the end. */
njn695c16e2005-03-27 03:40:28 +00004944 if (cgb_used < cgb_size) {
4945 cgb_used++;
4946 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004947 }
4948
4949 /* Ok, we have to allocate a new one. */
njn695c16e2005-03-27 03:40:28 +00004950 tl_assert(cgb_used == cgb_size);
4951 sz_new = (cgbs == NULL) ? 10 : (2 * cgb_size);
nethercote8b76fe52004-11-08 19:20:09 +00004952
sewardj9c606bd2008-09-18 18:12:50 +00004953 cgbs_new = VG_(malloc)( "mc.acb.1", sz_new * sizeof(CGenBlock) );
njn695c16e2005-03-27 03:40:28 +00004954 for (i = 0; i < cgb_used; i++)
4955 cgbs_new[i] = cgbs[i];
nethercote8b76fe52004-11-08 19:20:09 +00004956
njn695c16e2005-03-27 03:40:28 +00004957 if (cgbs != NULL)
4958 VG_(free)( cgbs );
4959 cgbs = cgbs_new;
nethercote8b76fe52004-11-08 19:20:09 +00004960
njn695c16e2005-03-27 03:40:28 +00004961 cgb_size = sz_new;
4962 cgb_used++;
4963 if (cgb_used > cgb_used_MAX)
4964 cgb_used_MAX = cgb_used;
4965 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004966}
4967
4968
4969static void show_client_block_stats ( void )
4970{
4971 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00004972 "general CBs: %llu allocs, %llu discards, %llu maxinuse, %llu search\n",
njn695c16e2005-03-27 03:40:28 +00004973 cgb_allocs, cgb_discards, cgb_used_MAX, cgb_search
nethercote8b76fe52004-11-08 19:20:09 +00004974 );
4975}
4976
nethercote8b76fe52004-11-08 19:20:09 +00004977
sewardj7ce71662008-05-02 10:33:15 +00004978/*------------------------------------------------------------*/
4979/*--- Client requests ---*/
4980/*------------------------------------------------------------*/
nethercote8b76fe52004-11-08 19:20:09 +00004981
njn51d827b2005-05-09 01:02:08 +00004982static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
nethercote8b76fe52004-11-08 19:20:09 +00004983{
4984 Int i;
4985 Bool ok;
4986 Addr bad_addr;
4987
njnfc26ff92004-11-22 19:12:49 +00004988 if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
sewardj7ce71662008-05-02 10:33:15 +00004989 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
4990 && VG_USERREQ__FREELIKE_BLOCK != arg[0]
4991 && VG_USERREQ__CREATE_MEMPOOL != arg[0]
4992 && VG_USERREQ__DESTROY_MEMPOOL != arg[0]
4993 && VG_USERREQ__MEMPOOL_ALLOC != arg[0]
4994 && VG_USERREQ__MEMPOOL_FREE != arg[0]
4995 && VG_USERREQ__MEMPOOL_TRIM != arg[0]
4996 && VG_USERREQ__MOVE_MEMPOOL != arg[0]
4997 && VG_USERREQ__MEMPOOL_CHANGE != arg[0]
4998 && VG_USERREQ__MEMPOOL_EXISTS != arg[0])
nethercote8b76fe52004-11-08 19:20:09 +00004999 return False;
5000
5001 switch (arg[0]) {
njndbf7ca72006-03-31 11:57:59 +00005002 case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE:
5003 ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
nethercote8b76fe52004-11-08 19:20:09 +00005004 if (!ok)
sewardj7ce71662008-05-02 10:33:15 +00005005 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00005006 *ret = ok ? (UWord)NULL : bad_addr;
sewardj8cf88b72005-07-08 01:29:33 +00005007 break;
nethercote8b76fe52004-11-08 19:20:09 +00005008
njndbf7ca72006-03-31 11:57:59 +00005009 case VG_USERREQ__CHECK_MEM_IS_DEFINED: {
nethercote8b76fe52004-11-08 19:20:09 +00005010 MC_ReadResult res;
sewardj7cf4e6b2008-05-01 20:24:26 +00005011 UInt otag = 0;
5012 res = is_mem_defined ( arg[1], arg[2], &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00005013 if (MC_AddrErr == res)
sewardj7ce71662008-05-02 10:33:15 +00005014 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00005015 else if (MC_ValueErr == res)
sewardj7ce71662008-05-02 10:33:15 +00005016 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/False, otag );
nethercote8b76fe52004-11-08 19:20:09 +00005017 *ret = ( res==MC_Ok ? (UWord)NULL : bad_addr );
sewardj8cf88b72005-07-08 01:29:33 +00005018 break;
nethercote8b76fe52004-11-08 19:20:09 +00005019 }
5020
5021 case VG_USERREQ__DO_LEAK_CHECK:
njn8225cc02009-03-09 22:52:24 +00005022 MC_(detect_memory_leaks)(tid, arg[1] ? LC_Summary : LC_Full);
sewardj8cf88b72005-07-08 01:29:33 +00005023 *ret = 0; /* return value is meaningless */
5024 break;
nethercote8b76fe52004-11-08 19:20:09 +00005025
njndbf7ca72006-03-31 11:57:59 +00005026 case VG_USERREQ__MAKE_MEM_NOACCESS:
5027 MC_(make_mem_noaccess) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00005028 *ret = -1;
5029 break;
nethercote8b76fe52004-11-08 19:20:09 +00005030
njndbf7ca72006-03-31 11:57:59 +00005031 case VG_USERREQ__MAKE_MEM_UNDEFINED:
sewardj7ce71662008-05-02 10:33:15 +00005032 make_mem_undefined_w_tid_and_okind ( arg[1], arg[2], tid,
5033 MC_OKIND_USER );
sewardjedc75ab2005-03-15 23:30:32 +00005034 *ret = -1;
sewardj8cf88b72005-07-08 01:29:33 +00005035 break;
nethercote8b76fe52004-11-08 19:20:09 +00005036
njndbf7ca72006-03-31 11:57:59 +00005037 case VG_USERREQ__MAKE_MEM_DEFINED:
5038 MC_(make_mem_defined) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00005039 *ret = -1;
nethercote8b76fe52004-11-08 19:20:09 +00005040 break;
5041
njndbf7ca72006-03-31 11:57:59 +00005042 case VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE:
5043 make_mem_defined_if_addressable ( arg[1], arg[2] );
sewardjfb1e9ad2006-03-10 13:41:58 +00005044 *ret = -1;
5045 break;
5046
sewardjedc75ab2005-03-15 23:30:32 +00005047 case VG_USERREQ__CREATE_BLOCK: /* describe a block */
sewardj8cf88b72005-07-08 01:29:33 +00005048 if (arg[1] != 0 && arg[2] != 0) {
5049 i = alloc_client_block();
5050 /* VG_(printf)("allocated %d %p\n", i, cgbs); */
5051 cgbs[i].start = arg[1];
5052 cgbs[i].size = arg[2];
sewardj9c606bd2008-09-18 18:12:50 +00005053 cgbs[i].desc = VG_(strdup)("mc.mhcr.1", (Char *)arg[3]);
sewardj39f34232007-11-09 23:02:28 +00005054 cgbs[i].where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
sewardj8cf88b72005-07-08 01:29:33 +00005055 *ret = i;
5056 } else
5057 *ret = -1;
5058 break;
sewardjedc75ab2005-03-15 23:30:32 +00005059
nethercote8b76fe52004-11-08 19:20:09 +00005060 case VG_USERREQ__DISCARD: /* discard */
njn695c16e2005-03-27 03:40:28 +00005061 if (cgbs == NULL
5062 || arg[2] >= cgb_used ||
sewardj8cf88b72005-07-08 01:29:33 +00005063 (cgbs[arg[2]].start == 0 && cgbs[arg[2]].size == 0)) {
sewardjedc75ab2005-03-15 23:30:32 +00005064 *ret = 1;
sewardj8cf88b72005-07-08 01:29:33 +00005065 } else {
5066 tl_assert(arg[2] >= 0 && arg[2] < cgb_used);
5067 cgbs[arg[2]].start = cgbs[arg[2]].size = 0;
5068 VG_(free)(cgbs[arg[2]].desc);
5069 cgb_discards++;
5070 *ret = 0;
5071 }
5072 break;
nethercote8b76fe52004-11-08 19:20:09 +00005073
sewardjc2c12c22006-03-08 13:20:09 +00005074 case VG_USERREQ__GET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00005075 *ret = mc_get_or_set_vbits_for_client
njn1dcee092009-02-24 03:07:37 +00005076 ( arg[1], arg[2], arg[3], False /* get them */ );
sewardjc2c12c22006-03-08 13:20:09 +00005077 break;
5078
5079 case VG_USERREQ__SET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00005080 *ret = mc_get_or_set_vbits_for_client
njn1dcee092009-02-24 03:07:37 +00005081 ( arg[1], arg[2], arg[3], True /* set them */ );
sewardjc2c12c22006-03-08 13:20:09 +00005082 break;
nethercote8b76fe52004-11-08 19:20:09 +00005083
njn1d0825f2006-03-27 11:37:07 +00005084 case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
5085 UWord** argp = (UWord**)arg;
5086 // MC_(bytes_leaked) et al were set by the last leak check (or zero
5087 // if no prior leak checks performed).
5088 *argp[1] = MC_(bytes_leaked) + MC_(bytes_indirect);
5089 *argp[2] = MC_(bytes_dubious);
5090 *argp[3] = MC_(bytes_reachable);
5091 *argp[4] = MC_(bytes_suppressed);
5092 // there is no argp[5]
5093 //*argp[5] = MC_(bytes_indirect);
njn8df80b22009-03-02 05:11:06 +00005094 // XXX need to make *argp[1-4] defined; currently done in the
5095 // VALGRIND_COUNT_LEAKS_MACRO by initialising them to zero.
5096 *ret = 0;
5097 return True;
5098 }
5099 case VG_USERREQ__COUNT_LEAK_BLOCKS: { /* count leaked blocks */
5100 UWord** argp = (UWord**)arg;
5101 // MC_(blocks_leaked) et al were set by the last leak check (or zero
5102 // if no prior leak checks performed).
5103 *argp[1] = MC_(blocks_leaked) + MC_(blocks_indirect);
5104 *argp[2] = MC_(blocks_dubious);
5105 *argp[3] = MC_(blocks_reachable);
5106 *argp[4] = MC_(blocks_suppressed);
5107 // there is no argp[5]
5108 //*argp[5] = MC_(blocks_indirect);
5109 // XXX need to make *argp[1-4] defined; currently done in the
5110 // VALGRIND_COUNT_LEAK_BLOCKS_MACRO by initialising them to zero.
njn1d0825f2006-03-27 11:37:07 +00005111 *ret = 0;
5112 return True;
5113 }
5114 case VG_USERREQ__MALLOCLIKE_BLOCK: {
5115 Addr p = (Addr)arg[1];
5116 SizeT sizeB = arg[2];
njn1dcee092009-02-24 03:07:37 +00005117 //UInt rzB = arg[3]; XXX: unused!
njn1d0825f2006-03-27 11:37:07 +00005118 Bool is_zeroed = (Bool)arg[4];
5119
njn1dcee092009-02-24 03:07:37 +00005120 MC_(new_block) ( tid, p, sizeB, /*ignored*/0, is_zeroed,
njn1d0825f2006-03-27 11:37:07 +00005121 MC_AllocCustom, MC_(malloc_list) );
5122 return True;
5123 }
5124 case VG_USERREQ__FREELIKE_BLOCK: {
5125 Addr p = (Addr)arg[1];
5126 UInt rzB = arg[2];
5127
5128 MC_(handle_free) ( tid, p, rzB, MC_AllocCustom );
5129 return True;
5130 }
5131
5132 case _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR: {
njn718d3b12006-12-16 00:54:12 +00005133 Char* s = (Char*)arg[1];
5134 Addr dst = (Addr) arg[2];
5135 Addr src = (Addr) arg[3];
5136 SizeT len = (SizeT)arg[4];
sewardj7ce71662008-05-02 10:33:15 +00005137 MC_(record_overlap_error)(tid, s, src, dst, len);
njn1d0825f2006-03-27 11:37:07 +00005138 return True;
5139 }
5140
5141 case VG_USERREQ__CREATE_MEMPOOL: {
5142 Addr pool = (Addr)arg[1];
5143 UInt rzB = arg[2];
5144 Bool is_zeroed = (Bool)arg[3];
5145
5146 MC_(create_mempool) ( pool, rzB, is_zeroed );
5147 return True;
5148 }
5149
5150 case VG_USERREQ__DESTROY_MEMPOOL: {
5151 Addr pool = (Addr)arg[1];
5152
5153 MC_(destroy_mempool) ( pool );
5154 return True;
5155 }
5156
5157 case VG_USERREQ__MEMPOOL_ALLOC: {
5158 Addr pool = (Addr)arg[1];
5159 Addr addr = (Addr)arg[2];
5160 UInt size = arg[3];
5161
5162 MC_(mempool_alloc) ( tid, pool, addr, size );
5163 return True;
5164 }
5165
5166 case VG_USERREQ__MEMPOOL_FREE: {
5167 Addr pool = (Addr)arg[1];
5168 Addr addr = (Addr)arg[2];
5169
5170 MC_(mempool_free) ( pool, addr );
5171 return True;
5172 }
5173
sewardj2c1c9df2006-07-28 00:06:37 +00005174 case VG_USERREQ__MEMPOOL_TRIM: {
5175 Addr pool = (Addr)arg[1];
5176 Addr addr = (Addr)arg[2];
5177 UInt size = arg[3];
5178
5179 MC_(mempool_trim) ( pool, addr, size );
5180 return True;
5181 }
5182
sewardjc740d762006-10-05 17:59:23 +00005183 case VG_USERREQ__MOVE_MEMPOOL: {
5184 Addr poolA = (Addr)arg[1];
5185 Addr poolB = (Addr)arg[2];
5186
5187 MC_(move_mempool) ( poolA, poolB );
5188 return True;
5189 }
5190
5191 case VG_USERREQ__MEMPOOL_CHANGE: {
5192 Addr pool = (Addr)arg[1];
5193 Addr addrA = (Addr)arg[2];
5194 Addr addrB = (Addr)arg[3];
5195 UInt size = arg[4];
5196
5197 MC_(mempool_change) ( pool, addrA, addrB, size );
5198 return True;
5199 }
5200
5201 case VG_USERREQ__MEMPOOL_EXISTS: {
5202 Addr pool = (Addr)arg[1];
5203
5204 *ret = (UWord) MC_(mempool_exists) ( pool );
5205 return True;
5206 }
5207
5208
nethercote8b76fe52004-11-08 19:20:09 +00005209 default:
sewardj6b523cd2009-07-15 14:49:40 +00005210 VG_(message)(
5211 Vg_UserMsg,
5212 "Warning: unknown memcheck client request code %llx\n",
5213 (ULong)arg[0]
5214 );
njn1d0825f2006-03-27 11:37:07 +00005215 return False;
nethercote8b76fe52004-11-08 19:20:09 +00005216 }
5217 return True;
5218}
njn25e49d8e72002-09-23 09:36:25 +00005219
njnf76d27a2009-05-28 01:53:07 +00005220
njn25e49d8e72002-09-23 09:36:25 +00005221/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +00005222/*--- Crude profiling machinery. ---*/
5223/*------------------------------------------------------------*/
5224
5225// We track a number of interesting events (using PROF_EVENT)
5226// if MC_PROFILE_MEMORY is defined.
5227
5228#ifdef MC_PROFILE_MEMORY
5229
5230UInt MC_(event_ctr)[N_PROF_EVENTS];
5231HChar* MC_(event_ctr_name)[N_PROF_EVENTS];
5232
5233static void init_prof_mem ( void )
5234{
5235 Int i;
5236 for (i = 0; i < N_PROF_EVENTS; i++) {
5237 MC_(event_ctr)[i] = 0;
5238 MC_(event_ctr_name)[i] = NULL;
5239 }
5240}
5241
5242static void done_prof_mem ( void )
5243{
5244 Int i;
5245 Bool spaced = False;
5246 for (i = 0; i < N_PROF_EVENTS; i++) {
5247 if (!spaced && (i % 10) == 0) {
5248 VG_(printf)("\n");
5249 spaced = True;
5250 }
5251 if (MC_(event_ctr)[i] > 0) {
5252 spaced = False;
5253 VG_(printf)( "prof mem event %3d: %9d %s\n",
5254 i, MC_(event_ctr)[i],
5255 MC_(event_ctr_name)[i]
5256 ? MC_(event_ctr_name)[i] : "unnamed");
5257 }
5258 }
5259}
5260
5261#else
5262
5263static void init_prof_mem ( void ) { }
5264static void done_prof_mem ( void ) { }
5265
5266#endif
5267
sewardj7cf4e6b2008-05-01 20:24:26 +00005268
5269/*------------------------------------------------------------*/
5270/*--- Origin tracking stuff ---*/
5271/*------------------------------------------------------------*/
5272
5273/*--------------------------------------------*/
5274/*--- Origin tracking: load handlers ---*/
5275/*--------------------------------------------*/
5276
5277static INLINE UInt merge_origins ( UInt or1, UInt or2 ) {
5278 return or1 > or2 ? or1 : or2;
5279}
5280
5281UWord VG_REGPARM(1) MC_(helperc_b_load1)( Addr a ) {
5282 OCacheLine* line;
5283 UChar descr;
5284 UWord lineoff = oc_line_offset(a);
5285 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5286
5287 if (OC_ENABLE_ASSERTIONS) {
5288 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5289 }
5290
5291 line = find_OCacheLine( a );
5292
5293 descr = line->descr[lineoff];
5294 if (OC_ENABLE_ASSERTIONS) {
5295 tl_assert(descr < 0x10);
5296 }
5297
5298 if (LIKELY(0 == (descr & (1 << byteoff)))) {
5299 return 0;
5300 } else {
5301 return line->w32[lineoff];
5302 }
5303}
5304
5305UWord VG_REGPARM(1) MC_(helperc_b_load2)( Addr a ) {
5306 OCacheLine* line;
5307 UChar descr;
5308 UWord lineoff, byteoff;
5309
5310 if (UNLIKELY(a & 1)) {
5311 /* Handle misaligned case, slowly. */
5312 UInt oLo = (UInt)MC_(helperc_b_load1)( a + 0 );
5313 UInt oHi = (UInt)MC_(helperc_b_load1)( a + 1 );
5314 return merge_origins(oLo, oHi);
5315 }
5316
5317 lineoff = oc_line_offset(a);
5318 byteoff = a & 3; /* 0 or 2 */
5319
5320 if (OC_ENABLE_ASSERTIONS) {
5321 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5322 }
5323 line = find_OCacheLine( a );
5324
5325 descr = line->descr[lineoff];
5326 if (OC_ENABLE_ASSERTIONS) {
5327 tl_assert(descr < 0x10);
5328 }
5329
5330 if (LIKELY(0 == (descr & (3 << byteoff)))) {
5331 return 0;
5332 } else {
5333 return line->w32[lineoff];
5334 }
5335}
5336
5337UWord VG_REGPARM(1) MC_(helperc_b_load4)( Addr a ) {
5338 OCacheLine* line;
5339 UChar descr;
5340 UWord lineoff;
5341
5342 if (UNLIKELY(a & 3)) {
5343 /* Handle misaligned case, slowly. */
5344 UInt oLo = (UInt)MC_(helperc_b_load2)( a + 0 );
5345 UInt oHi = (UInt)MC_(helperc_b_load2)( a + 2 );
5346 return merge_origins(oLo, oHi);
5347 }
5348
5349 lineoff = oc_line_offset(a);
5350 if (OC_ENABLE_ASSERTIONS) {
5351 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5352 }
5353
5354 line = find_OCacheLine( a );
5355
5356 descr = line->descr[lineoff];
5357 if (OC_ENABLE_ASSERTIONS) {
5358 tl_assert(descr < 0x10);
5359 }
5360
5361 if (LIKELY(0 == descr)) {
5362 return 0;
5363 } else {
5364 return line->w32[lineoff];
5365 }
5366}
5367
5368UWord VG_REGPARM(1) MC_(helperc_b_load8)( Addr a ) {
5369 OCacheLine* line;
5370 UChar descrLo, descrHi, descr;
5371 UWord lineoff;
5372
5373 if (UNLIKELY(a & 7)) {
5374 /* Handle misaligned case, slowly. */
5375 UInt oLo = (UInt)MC_(helperc_b_load4)( a + 0 );
5376 UInt oHi = (UInt)MC_(helperc_b_load4)( a + 4 );
5377 return merge_origins(oLo, oHi);
5378 }
5379
5380 lineoff = oc_line_offset(a);
5381 if (OC_ENABLE_ASSERTIONS) {
5382 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5383 }
5384
5385 line = find_OCacheLine( a );
5386
5387 descrLo = line->descr[lineoff + 0];
5388 descrHi = line->descr[lineoff + 1];
5389 descr = descrLo | descrHi;
5390 if (OC_ENABLE_ASSERTIONS) {
5391 tl_assert(descr < 0x10);
5392 }
5393
5394 if (LIKELY(0 == descr)) {
5395 return 0; /* both 32-bit chunks are defined */
5396 } else {
5397 UInt oLo = descrLo == 0 ? 0 : line->w32[lineoff + 0];
5398 UInt oHi = descrHi == 0 ? 0 : line->w32[lineoff + 1];
5399 return merge_origins(oLo, oHi);
5400 }
5401}
5402
5403UWord VG_REGPARM(1) MC_(helperc_b_load16)( Addr a ) {
5404 UInt oLo = (UInt)MC_(helperc_b_load8)( a + 0 );
5405 UInt oHi = (UInt)MC_(helperc_b_load8)( a + 8 );
5406 UInt oBoth = merge_origins(oLo, oHi);
5407 return (UWord)oBoth;
5408}
5409
5410
5411/*--------------------------------------------*/
5412/*--- Origin tracking: store handlers ---*/
5413/*--------------------------------------------*/
5414
5415void VG_REGPARM(2) MC_(helperc_b_store1)( Addr a, UWord d32 ) {
5416 OCacheLine* line;
5417 UWord lineoff = oc_line_offset(a);
5418 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5419
5420 if (OC_ENABLE_ASSERTIONS) {
5421 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5422 }
5423
5424 line = find_OCacheLine( a );
5425
5426 if (d32 == 0) {
5427 line->descr[lineoff] &= ~(1 << byteoff);
5428 } else {
5429 line->descr[lineoff] |= (1 << byteoff);
5430 line->w32[lineoff] = d32;
5431 }
5432}
5433
5434void VG_REGPARM(2) MC_(helperc_b_store2)( Addr a, UWord d32 ) {
5435 OCacheLine* line;
5436 UWord lineoff, byteoff;
5437
5438 if (UNLIKELY(a & 1)) {
5439 /* Handle misaligned case, slowly. */
5440 MC_(helperc_b_store1)( a + 0, d32 );
5441 MC_(helperc_b_store1)( a + 1, d32 );
5442 return;
5443 }
5444
5445 lineoff = oc_line_offset(a);
5446 byteoff = a & 3; /* 0 or 2 */
5447
5448 if (OC_ENABLE_ASSERTIONS) {
5449 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5450 }
5451
5452 line = find_OCacheLine( a );
5453
5454 if (d32 == 0) {
5455 line->descr[lineoff] &= ~(3 << byteoff);
5456 } else {
5457 line->descr[lineoff] |= (3 << byteoff);
5458 line->w32[lineoff] = d32;
5459 }
5460}
5461
5462void VG_REGPARM(2) MC_(helperc_b_store4)( Addr a, UWord d32 ) {
5463 OCacheLine* line;
5464 UWord lineoff;
5465
5466 if (UNLIKELY(a & 3)) {
5467 /* Handle misaligned case, slowly. */
5468 MC_(helperc_b_store2)( a + 0, d32 );
5469 MC_(helperc_b_store2)( a + 2, d32 );
5470 return;
5471 }
5472
5473 lineoff = oc_line_offset(a);
5474 if (OC_ENABLE_ASSERTIONS) {
5475 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5476 }
5477
5478 line = find_OCacheLine( a );
5479
5480 if (d32 == 0) {
5481 line->descr[lineoff] = 0;
5482 } else {
5483 line->descr[lineoff] = 0xF;
5484 line->w32[lineoff] = d32;
5485 }
5486}
5487
5488void VG_REGPARM(2) MC_(helperc_b_store8)( Addr a, UWord d32 ) {
5489 OCacheLine* line;
5490 UWord lineoff;
5491
5492 if (UNLIKELY(a & 7)) {
5493 /* Handle misaligned case, slowly. */
5494 MC_(helperc_b_store4)( a + 0, d32 );
5495 MC_(helperc_b_store4)( a + 4, d32 );
5496 return;
5497 }
5498
5499 lineoff = oc_line_offset(a);
5500 if (OC_ENABLE_ASSERTIONS) {
5501 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5502 }
5503
5504 line = find_OCacheLine( a );
5505
5506 if (d32 == 0) {
5507 line->descr[lineoff + 0] = 0;
5508 line->descr[lineoff + 1] = 0;
5509 } else {
5510 line->descr[lineoff + 0] = 0xF;
5511 line->descr[lineoff + 1] = 0xF;
5512 line->w32[lineoff + 0] = d32;
5513 line->w32[lineoff + 1] = d32;
5514 }
5515}
5516
5517void VG_REGPARM(2) MC_(helperc_b_store16)( Addr a, UWord d32 ) {
5518 MC_(helperc_b_store8)( a + 0, d32 );
5519 MC_(helperc_b_store8)( a + 8, d32 );
5520}
5521
5522
5523/*--------------------------------------------*/
5524/*--- Origin tracking: sarp handlers ---*/
5525/*--------------------------------------------*/
5526
5527__attribute__((noinline))
5528static void ocache_sarp_Set_Origins ( Addr a, UWord len, UInt otag ) {
5529 if ((a & 1) && len >= 1) {
5530 MC_(helperc_b_store1)( a, otag );
5531 a++;
5532 len--;
5533 }
5534 if ((a & 2) && len >= 2) {
5535 MC_(helperc_b_store2)( a, otag );
5536 a += 2;
5537 len -= 2;
5538 }
5539 if (len >= 4)
5540 tl_assert(0 == (a & 3));
5541 while (len >= 4) {
5542 MC_(helperc_b_store4)( a, otag );
5543 a += 4;
5544 len -= 4;
5545 }
5546 if (len >= 2) {
5547 MC_(helperc_b_store2)( a, otag );
5548 a += 2;
5549 len -= 2;
5550 }
5551 if (len >= 1) {
5552 MC_(helperc_b_store1)( a, otag );
njn4c245e52009-03-15 23:25:38 +00005553 //a++;
sewardj7cf4e6b2008-05-01 20:24:26 +00005554 len--;
5555 }
5556 tl_assert(len == 0);
5557}
5558
5559__attribute__((noinline))
5560static void ocache_sarp_Clear_Origins ( Addr a, UWord len ) {
5561 if ((a & 1) && len >= 1) {
5562 MC_(helperc_b_store1)( a, 0 );
5563 a++;
5564 len--;
5565 }
5566 if ((a & 2) && len >= 2) {
5567 MC_(helperc_b_store2)( a, 0 );
5568 a += 2;
5569 len -= 2;
5570 }
5571 if (len >= 4)
5572 tl_assert(0 == (a & 3));
5573 while (len >= 4) {
5574 MC_(helperc_b_store4)( a, 0 );
5575 a += 4;
5576 len -= 4;
5577 }
5578 if (len >= 2) {
5579 MC_(helperc_b_store2)( a, 0 );
5580 a += 2;
5581 len -= 2;
5582 }
5583 if (len >= 1) {
5584 MC_(helperc_b_store1)( a, 0 );
njn4c245e52009-03-15 23:25:38 +00005585 //a++;
sewardj7cf4e6b2008-05-01 20:24:26 +00005586 len--;
5587 }
5588 tl_assert(len == 0);
5589}
5590
5591
njn1d0825f2006-03-27 11:37:07 +00005592/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00005593/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00005594/*------------------------------------------------------------*/
5595
njn51d827b2005-05-09 01:02:08 +00005596static void mc_post_clo_init ( void )
njn5c004e42002-11-18 11:04:50 +00005597{
sewardj71bc3cb2005-05-19 00:25:45 +00005598 /* If we've been asked to emit XML, mash around various other
5599 options so as to constrain the output somewhat. */
5600 if (VG_(clo_xml)) {
5601 /* Extract as much info as possible from the leak checker. */
njn1d0825f2006-03-27 11:37:07 +00005602 /* MC_(clo_show_reachable) = True; */
5603 MC_(clo_leak_check) = LC_Full;
sewardj71bc3cb2005-05-19 00:25:45 +00005604 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005605
5606 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
5607
5608 if (MC_(clo_mc_level) == 3) {
5609 /* We're doing origin tracking. */
5610# ifdef PERF_FAST_STACK
5611 VG_(track_new_mem_stack_4_w_ECU) ( mc_new_mem_stack_4_w_ECU );
5612 VG_(track_new_mem_stack_8_w_ECU) ( mc_new_mem_stack_8_w_ECU );
5613 VG_(track_new_mem_stack_12_w_ECU) ( mc_new_mem_stack_12_w_ECU );
5614 VG_(track_new_mem_stack_16_w_ECU) ( mc_new_mem_stack_16_w_ECU );
5615 VG_(track_new_mem_stack_32_w_ECU) ( mc_new_mem_stack_32_w_ECU );
5616 VG_(track_new_mem_stack_112_w_ECU) ( mc_new_mem_stack_112_w_ECU );
5617 VG_(track_new_mem_stack_128_w_ECU) ( mc_new_mem_stack_128_w_ECU );
5618 VG_(track_new_mem_stack_144_w_ECU) ( mc_new_mem_stack_144_w_ECU );
5619 VG_(track_new_mem_stack_160_w_ECU) ( mc_new_mem_stack_160_w_ECU );
5620# endif
5621 VG_(track_new_mem_stack_w_ECU) ( mc_new_mem_stack_w_ECU );
5622 } else {
5623 /* Not doing origin tracking */
5624# ifdef PERF_FAST_STACK
5625 VG_(track_new_mem_stack_4) ( mc_new_mem_stack_4 );
5626 VG_(track_new_mem_stack_8) ( mc_new_mem_stack_8 );
5627 VG_(track_new_mem_stack_12) ( mc_new_mem_stack_12 );
5628 VG_(track_new_mem_stack_16) ( mc_new_mem_stack_16 );
5629 VG_(track_new_mem_stack_32) ( mc_new_mem_stack_32 );
5630 VG_(track_new_mem_stack_112) ( mc_new_mem_stack_112 );
5631 VG_(track_new_mem_stack_128) ( mc_new_mem_stack_128 );
5632 VG_(track_new_mem_stack_144) ( mc_new_mem_stack_144 );
5633 VG_(track_new_mem_stack_160) ( mc_new_mem_stack_160 );
5634# endif
5635 VG_(track_new_mem_stack) ( mc_new_mem_stack );
5636 }
sewardj9d624d12008-05-02 13:35:29 +00005637
5638 /* This origin tracking cache is huge (~100M), so only initialise
5639 if we need it. */
5640 if (MC_(clo_mc_level) >= 3) {
5641 init_OCache();
sewardj77139802008-05-05 09:48:56 +00005642 tl_assert(ocacheL1 != NULL);
sewardj9d624d12008-05-02 13:35:29 +00005643 tl_assert(ocacheL2 != NULL);
5644 } else {
sewardj77139802008-05-05 09:48:56 +00005645 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005646 tl_assert(ocacheL2 == NULL);
5647 }
njn5c004e42002-11-18 11:04:50 +00005648}
5649
njn1d0825f2006-03-27 11:37:07 +00005650static void print_SM_info(char* type, int n_SMs)
5651{
5652 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005653 " memcheck: SMs: %s = %d (%ldk, %ldM)\n",
njn1d0825f2006-03-27 11:37:07 +00005654 type,
5655 n_SMs,
barta0b6b2c2008-07-07 06:49:24 +00005656 n_SMs * sizeof(SecMap) / 1024UL,
5657 n_SMs * sizeof(SecMap) / (1024 * 1024UL) );
njn1d0825f2006-03-27 11:37:07 +00005658}
5659
njn51d827b2005-05-09 01:02:08 +00005660static void mc_fini ( Int exitcode )
njn5c004e42002-11-18 11:04:50 +00005661{
njn1d0825f2006-03-27 11:37:07 +00005662 MC_(print_malloc_stats)();
sewardj23eb2fd2005-04-22 16:29:19 +00005663
sewardj2d9e8742009-08-07 15:46:56 +00005664 if (MC_(clo_leak_check) != LC_Off) {
5665 MC_(detect_memory_leaks)(1/*bogus ThreadId*/, MC_(clo_leak_check));
njnb6267bd2009-08-12 00:14:16 +00005666 } else {
5667 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5668 VG_(umsg)(
5669 "For a detailed leak analysis, rerun with: --leak-check=full\n"
5670 "\n"
5671 );
5672 }
sewardj2d9e8742009-08-07 15:46:56 +00005673 }
5674
5675 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5676 VG_(message)(Vg_UserMsg,
5677 "For counts of detected and suppressed errors, rerun with: -v\n");
5678 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005679
sewardj7ce71662008-05-02 10:33:15 +00005680 if (MC_(any_value_errors) && !VG_(clo_xml) && VG_(clo_verbosity) >= 1
sewardj7cf4e6b2008-05-01 20:24:26 +00005681 && MC_(clo_mc_level) == 2) {
5682 VG_(message)(Vg_UserMsg,
5683 "Use --track-origins=yes to see where "
sewardj6b523cd2009-07-15 14:49:40 +00005684 "uninitialised values come from\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00005685 }
5686
njn1d0825f2006-03-27 11:37:07 +00005687 done_prof_mem();
sewardjae986ca2005-10-12 12:53:20 +00005688
sewardj2d9e8742009-08-07 15:46:56 +00005689 if (VG_(clo_stats)) {
njn1d0825f2006-03-27 11:37:07 +00005690 SizeT max_secVBit_szB, max_SMs_szB, max_shmem_szB;
5691
sewardj45d94cc2005-04-20 14:44:11 +00005692 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005693 " memcheck: sanity checks: %d cheap, %d expensive\n",
sewardj23eb2fd2005-04-22 16:29:19 +00005694 n_sanity_cheap, n_sanity_expensive );
sewardj45d94cc2005-04-20 14:44:11 +00005695 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005696 " memcheck: auxmaps: %lld auxmap entries (%lldk, %lldM) in use\n",
sewardj05a46732006-10-17 01:28:10 +00005697 n_auxmap_L2_nodes,
5698 n_auxmap_L2_nodes * 64,
5699 n_auxmap_L2_nodes / 16 );
sewardj23eb2fd2005-04-22 16:29:19 +00005700 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005701 " memcheck: auxmaps_L1: %lld searches, %lld cmps, ratio %lld:10\n",
sewardj05a46732006-10-17 01:28:10 +00005702 n_auxmap_L1_searches, n_auxmap_L1_cmps,
5703 (10ULL * n_auxmap_L1_cmps)
5704 / (n_auxmap_L1_searches ? n_auxmap_L1_searches : 1)
5705 );
5706 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005707 " memcheck: auxmaps_L2: %lld searches, %lld nodes\n",
sewardj05a46732006-10-17 01:28:10 +00005708 n_auxmap_L2_searches, n_auxmap_L2_nodes
5709 );
sewardj23eb2fd2005-04-22 16:29:19 +00005710
njndbf7ca72006-03-31 11:57:59 +00005711 print_SM_info("n_issued ", n_issued_SMs);
5712 print_SM_info("n_deissued ", n_deissued_SMs);
5713 print_SM_info("max_noaccess ", max_noaccess_SMs);
5714 print_SM_info("max_undefined", max_undefined_SMs);
5715 print_SM_info("max_defined ", max_defined_SMs);
5716 print_SM_info("max_non_DSM ", max_non_DSM_SMs);
njn1d0825f2006-03-27 11:37:07 +00005717
5718 // Three DSMs, plus the non-DSM ones
5719 max_SMs_szB = (3 + max_non_DSM_SMs) * sizeof(SecMap);
5720 // The 3*sizeof(Word) bytes is the AVL node metadata size.
5721 // The 4*sizeof(Word) bytes is the malloc metadata size.
5722 // Hardwiring these sizes in sucks, but I don't see how else to do it.
5723 max_secVBit_szB = max_secVBit_nodes *
5724 (sizeof(SecVBitNode) + 3*sizeof(Word) + 4*sizeof(Word));
5725 max_shmem_szB = sizeof(primary_map) + max_SMs_szB + max_secVBit_szB;
sewardj23eb2fd2005-04-22 16:29:19 +00005726
5727 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005728 " memcheck: max sec V bit nodes: %d (%ldk, %ldM)\n",
njn1d0825f2006-03-27 11:37:07 +00005729 max_secVBit_nodes, max_secVBit_szB / 1024,
5730 max_secVBit_szB / (1024 * 1024));
5731 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005732 " memcheck: set_sec_vbits8 calls: %llu (new: %llu, updates: %llu)\n",
njn1d0825f2006-03-27 11:37:07 +00005733 sec_vbits_new_nodes + sec_vbits_updates,
5734 sec_vbits_new_nodes, sec_vbits_updates );
5735 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005736 " memcheck: max shadow mem size: %ldk, %ldM\n",
njn1d0825f2006-03-27 11:37:07 +00005737 max_shmem_szB / 1024, max_shmem_szB / (1024 * 1024));
sewardj7cf4e6b2008-05-01 20:24:26 +00005738
5739 if (MC_(clo_mc_level) >= 3) {
5740 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005741 " ocacheL1: %'12lu refs %'12lu misses (%'lu lossage)\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005742 stats_ocacheL1_find,
5743 stats_ocacheL1_misses,
5744 stats_ocacheL1_lossage );
5745 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005746 " ocacheL1: %'12lu at 0 %'12lu at 1\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005747 stats_ocacheL1_find - stats_ocacheL1_misses
5748 - stats_ocacheL1_found_at_1
5749 - stats_ocacheL1_found_at_N,
5750 stats_ocacheL1_found_at_1 );
5751 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005752 " ocacheL1: %'12lu at 2+ %'12lu move-fwds\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005753 stats_ocacheL1_found_at_N,
5754 stats_ocacheL1_movefwds );
5755 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005756 " ocacheL1: %'12lu sizeB %'12u useful\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005757 (UWord)sizeof(OCache),
5758 4 * OC_W32S_PER_LINE * OC_LINES_PER_SET * OC_N_SETS );
5759 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005760 " ocacheL2: %'12lu refs %'12lu misses\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005761 stats__ocacheL2_refs,
5762 stats__ocacheL2_misses );
5763 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005764 " ocacheL2: %'9lu max nodes %'9lu curr nodes\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005765 stats__ocacheL2_n_nodes_max,
5766 stats__ocacheL2_n_nodes );
5767 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005768 " niacache: %'12lu refs %'12lu misses\n",
sewardj7cf4e6b2008-05-01 20:24:26 +00005769 stats__nia_cache_queries, stats__nia_cache_misses);
sewardj9d624d12008-05-02 13:35:29 +00005770 } else {
sewardj77139802008-05-05 09:48:56 +00005771 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005772 tl_assert(ocacheL2 == NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00005773 }
sewardj45d94cc2005-04-20 14:44:11 +00005774 }
5775
njn5c004e42002-11-18 11:04:50 +00005776 if (0) {
5777 VG_(message)(Vg_DebugMsg,
sewardj6b523cd2009-07-15 14:49:40 +00005778 "------ Valgrind's client block stats follow ---------------\n" );
nethercote8b76fe52004-11-08 19:20:09 +00005779 show_client_block_stats();
njn5c004e42002-11-18 11:04:50 +00005780 }
njn25e49d8e72002-09-23 09:36:25 +00005781}
5782
njn51d827b2005-05-09 01:02:08 +00005783static void mc_pre_clo_init(void)
5784{
5785 VG_(details_name) ("Memcheck");
5786 VG_(details_version) (NULL);
5787 VG_(details_description) ("a memory error detector");
5788 VG_(details_copyright_author)(
sewardj9eecbbb2010-05-03 21:37:12 +00005789 "Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.");
njn51d827b2005-05-09 01:02:08 +00005790 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj1e0fff62011-01-10 15:01:03 +00005791 VG_(details_avg_translation_sizeB) ( 640 );
njn51d827b2005-05-09 01:02:08 +00005792
5793 VG_(basic_tool_funcs) (mc_post_clo_init,
5794 MC_(instrument),
5795 mc_fini);
5796
sewardj81651dc2007-08-28 06:05:20 +00005797 VG_(needs_final_IR_tidy_pass) ( MC_(final_tidy) );
5798
5799
njn51d827b2005-05-09 01:02:08 +00005800 VG_(needs_core_errors) ();
sewardj7ce71662008-05-02 10:33:15 +00005801 VG_(needs_tool_errors) (MC_(eq_Error),
sewardj6b523cd2009-07-15 14:49:40 +00005802 MC_(before_pp_Error),
sewardj7ce71662008-05-02 10:33:15 +00005803 MC_(pp_Error),
sewardj39f34232007-11-09 23:02:28 +00005804 True,/*show TIDs for errors*/
sewardj7ce71662008-05-02 10:33:15 +00005805 MC_(update_Error_extra),
5806 MC_(is_recognised_suppression),
5807 MC_(read_extra_suppression_info),
5808 MC_(error_matches_suppression),
5809 MC_(get_error_name),
sewardj588adef2009-08-15 22:41:51 +00005810 MC_(get_extra_suppression_info));
njn51d827b2005-05-09 01:02:08 +00005811 VG_(needs_libc_freeres) ();
njn1d0825f2006-03-27 11:37:07 +00005812 VG_(needs_command_line_options)(mc_process_cmd_line_options,
njn51d827b2005-05-09 01:02:08 +00005813 mc_print_usage,
5814 mc_print_debug_usage);
5815 VG_(needs_client_requests) (mc_handle_client_request);
5816 VG_(needs_sanity_checks) (mc_cheap_sanity_check,
5817 mc_expensive_sanity_check);
njn1d0825f2006-03-27 11:37:07 +00005818 VG_(needs_malloc_replacement) (MC_(malloc),
5819 MC_(__builtin_new),
5820 MC_(__builtin_vec_new),
5821 MC_(memalign),
5822 MC_(calloc),
5823 MC_(free),
5824 MC_(__builtin_delete),
5825 MC_(__builtin_vec_delete),
5826 MC_(realloc),
njn8b140de2009-02-17 04:31:18 +00005827 MC_(malloc_usable_size),
njn1d0825f2006-03-27 11:37:07 +00005828 MC_MALLOC_REDZONE_SZB );
sewardj6b523cd2009-07-15 14:49:40 +00005829
njnca54af32006-04-16 10:25:43 +00005830 VG_(needs_xml_output) ();
njn51d827b2005-05-09 01:02:08 +00005831
njn1d0825f2006-03-27 11:37:07 +00005832 VG_(track_new_mem_startup) ( mc_new_mem_startup );
sewardj7cf4e6b2008-05-01 20:24:26 +00005833 VG_(track_new_mem_stack_signal)( make_mem_undefined_w_tid );
njnbac8ede2009-07-24 19:09:52 +00005834 // We assume that brk()/sbrk() does not initialise new memory. Is this
5835 // accurate? John Reiser says:
5836 //
5837 // 0) sbrk() can *decrease* process address space. No zero fill is done
5838 // for a decrease, not even the fragment on the high end of the last page
5839 // that is beyond the new highest address. For maximum safety and
5840 // portability, then the bytes in the last page that reside above [the
5841 // new] sbrk(0) should be considered to be uninitialized, but in practice
5842 // it is exceedingly likely that they will retain their previous
5843 // contents.
5844 //
5845 // 1) If an increase is large enough to require new whole pages, then
5846 // those new whole pages (like all new pages) are zero-filled by the
5847 // operating system. So if sbrk(0) already is page aligned, then
5848 // sbrk(PAGE_SIZE) *does* zero-fill the new memory.
5849 //
5850 // 2) Any increase that lies within an existing allocated page is not
5851 // changed. So if (x = sbrk(0)) is not page aligned, then
5852 // sbrk(PAGE_SIZE) yields ((PAGE_SIZE -1) & -x) bytes which keep their
5853 // existing contents, and an additional PAGE_SIZE bytes which are zeroed.
5854 // ((PAGE_SIZE -1) & x) of them are "covered" by the sbrk(), and the rest
5855 // of them come along for the ride because the operating system deals
5856 // only in whole pages. Again, for maximum safety and portability, then
5857 // anything that lives above [the new] sbrk(0) should be considered
5858 // uninitialized, but in practice will retain previous contents [zero in
5859 // this case.]"
5860 //
5861 // In short:
5862 //
5863 // A key property of sbrk/brk is that new whole pages that are supplied
5864 // by the operating system *do* get initialized to zero.
5865 //
5866 // As for the portability of all this:
5867 //
5868 // sbrk and brk are not POSIX. However, any system that is a derivative
5869 // of *nix has sbrk and brk because there are too many softwares (such as
5870 // the Bourne shell) which rely on the traditional memory map (.text,
5871 // .data+.bss, stack) and the existence of sbrk/brk.
5872 //
5873 // So we should arguably observe all this. However:
5874 // - The current inaccuracy has caused maybe one complaint in seven years(?)
sewardj6f95e7e2010-01-27 10:28:00 +00005875 // - Relying on the zeroed-ness of whole brk'd pages is pretty grotty... I
njnbac8ede2009-07-24 19:09:52 +00005876 // doubt most programmers know the above information.
5877 // So I'm not terribly unhappy with marking it as undefined. --njn.
njn059acbf2009-08-05 05:05:15 +00005878 //
5879 // [More: I think most of what John said only applies to sbrk(). It seems
5880 // that brk() always deals in whole pages. And since this event deals
5881 // directly with brk(), not with sbrk(), perhaps it would be reasonable to
5882 // just mark all memory it allocates as defined.]
5883 //
sewardj7cf4e6b2008-05-01 20:24:26 +00005884 VG_(track_new_mem_brk) ( make_mem_undefined_w_tid );
sewardj6f95e7e2010-01-27 10:28:00 +00005885
5886 // Handling of mmap and mprotect isn't simple (well, it is simple,
5887 // but the justification isn't.) See comments above, just prior to
5888 // mc_new_mem_mmap.
njn1d0825f2006-03-27 11:37:07 +00005889 VG_(track_new_mem_mmap) ( mc_new_mem_mmap );
sewardj6f95e7e2010-01-27 10:28:00 +00005890 VG_(track_change_mem_mprotect) ( mc_new_mem_mprotect );
njn51d827b2005-05-09 01:02:08 +00005891
njn1d0825f2006-03-27 11:37:07 +00005892 VG_(track_copy_mem_remap) ( MC_(copy_address_range_state) );
njn81623712005-10-07 04:48:37 +00005893
njndbf7ca72006-03-31 11:57:59 +00005894 VG_(track_die_mem_stack_signal)( MC_(make_mem_noaccess) );
5895 VG_(track_die_mem_brk) ( MC_(make_mem_noaccess) );
5896 VG_(track_die_mem_munmap) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005897
sewardj7cf4e6b2008-05-01 20:24:26 +00005898 /* Defer the specification of the new_mem_stack functions to the
5899 post_clo_init function, since we need to first parse the command
5900 line before deciding which set to use. */
njn51d827b2005-05-09 01:02:08 +00005901
sewardj7cf4e6b2008-05-01 20:24:26 +00005902# ifdef PERF_FAST_STACK
njn1d0825f2006-03-27 11:37:07 +00005903 VG_(track_die_mem_stack_4) ( mc_die_mem_stack_4 );
5904 VG_(track_die_mem_stack_8) ( mc_die_mem_stack_8 );
5905 VG_(track_die_mem_stack_12) ( mc_die_mem_stack_12 );
5906 VG_(track_die_mem_stack_16) ( mc_die_mem_stack_16 );
5907 VG_(track_die_mem_stack_32) ( mc_die_mem_stack_32 );
5908 VG_(track_die_mem_stack_112) ( mc_die_mem_stack_112 );
5909 VG_(track_die_mem_stack_128) ( mc_die_mem_stack_128 );
5910 VG_(track_die_mem_stack_144) ( mc_die_mem_stack_144 );
5911 VG_(track_die_mem_stack_160) ( mc_die_mem_stack_160 );
sewardj7cf4e6b2008-05-01 20:24:26 +00005912# endif
njn1d0825f2006-03-27 11:37:07 +00005913 VG_(track_die_mem_stack) ( mc_die_mem_stack );
njn51d827b2005-05-09 01:02:08 +00005914
njndbf7ca72006-03-31 11:57:59 +00005915 VG_(track_ban_mem_stack) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005916
njndbf7ca72006-03-31 11:57:59 +00005917 VG_(track_pre_mem_read) ( check_mem_is_defined );
5918 VG_(track_pre_mem_read_asciiz) ( check_mem_is_defined_asciiz );
5919 VG_(track_pre_mem_write) ( check_mem_is_addressable );
njn1d0825f2006-03-27 11:37:07 +00005920 VG_(track_post_mem_write) ( mc_post_mem_write );
njn51d827b2005-05-09 01:02:08 +00005921
sewardj7cf4e6b2008-05-01 20:24:26 +00005922 if (MC_(clo_mc_level) >= 2)
njn1d0825f2006-03-27 11:37:07 +00005923 VG_(track_pre_reg_read) ( mc_pre_reg_read );
njn51d827b2005-05-09 01:02:08 +00005924
njn1d0825f2006-03-27 11:37:07 +00005925 VG_(track_post_reg_write) ( mc_post_reg_write );
5926 VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
njn51d827b2005-05-09 01:02:08 +00005927
5928 init_shadow_memory();
sewardj3f94a7d2007-08-25 07:19:08 +00005929 MC_(malloc_list) = VG_(HT_construct)( "MC_(malloc_list)" );
5930 MC_(mempool_list) = VG_(HT_construct)( "MC_(mempool_list)" );
njn1d0825f2006-03-27 11:37:07 +00005931 init_prof_mem();
njn51d827b2005-05-09 01:02:08 +00005932
5933 tl_assert( mc_expensive_sanity_check() );
njn1d0825f2006-03-27 11:37:07 +00005934
5935 // {LOADV,STOREV}[8421] will all fail horribly if this isn't true.
5936 tl_assert(sizeof(UWord) == sizeof(Addr));
sewardj05a46732006-10-17 01:28:10 +00005937 // Call me paranoid. I don't care.
5938 tl_assert(sizeof(void*) == sizeof(Addr));
njn1d0825f2006-03-27 11:37:07 +00005939
5940 // BYTES_PER_SEC_VBIT_NODE must be a power of two.
5941 tl_assert(-1 != VG_(log2)(BYTES_PER_SEC_VBIT_NODE));
sewardj7cf4e6b2008-05-01 20:24:26 +00005942
sewardj9d624d12008-05-02 13:35:29 +00005943 /* This is small. Always initialise it. */
sewardj7cf4e6b2008-05-01 20:24:26 +00005944 init_nia_to_ecu_cache();
sewardj7244e712008-05-02 12:35:48 +00005945
sewardj77139802008-05-05 09:48:56 +00005946 /* We can't initialise ocacheL1/ocacheL2 yet, since we don't know
5947 if we need to, since the command line args haven't been
5948 processed yet. Hence defer it to mc_post_clo_init. */
5949 tl_assert(ocacheL1 == NULL);
sewardj9d624d12008-05-02 13:35:29 +00005950 tl_assert(ocacheL2 == NULL);
5951
sewardj7244e712008-05-02 12:35:48 +00005952 /* Check some important stuff. See extensive comments above
5953 re UNALIGNED_OR_HIGH for background. */
5954# if VG_WORDSIZE == 4
5955 tl_assert(sizeof(void*) == 4);
5956 tl_assert(sizeof(Addr) == 4);
5957 tl_assert(sizeof(UWord) == 4);
5958 tl_assert(sizeof(Word) == 4);
5959 tl_assert(MAX_PRIMARY_ADDRESS == 0xFFFFFFFFUL);
5960 tl_assert(MASK(1) == 0UL);
5961 tl_assert(MASK(2) == 1UL);
5962 tl_assert(MASK(4) == 3UL);
5963 tl_assert(MASK(8) == 7UL);
5964# else
5965 tl_assert(VG_WORDSIZE == 8);
5966 tl_assert(sizeof(void*) == 8);
5967 tl_assert(sizeof(Addr) == 8);
5968 tl_assert(sizeof(UWord) == 8);
5969 tl_assert(sizeof(Word) == 8);
5970 tl_assert(MAX_PRIMARY_ADDRESS == 0x7FFFFFFFFULL);
5971 tl_assert(MASK(1) == 0xFFFFFFF800000000ULL);
5972 tl_assert(MASK(2) == 0xFFFFFFF800000001ULL);
5973 tl_assert(MASK(4) == 0xFFFFFFF800000003ULL);
5974 tl_assert(MASK(8) == 0xFFFFFFF800000007ULL);
5975# endif
njn51d827b2005-05-09 01:02:08 +00005976}
5977
sewardj45f4e7c2005-09-27 19:20:21 +00005978VG_DETERMINE_INTERFACE_VERSION(mc_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00005979
njn25e49d8e72002-09-23 09:36:25 +00005980/*--------------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00005981/*--- end mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005982/*--------------------------------------------------------------------*/