blob: 2d54fb9291fccbf15830f777d335ffa3d3a45617 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
njnc9539842002-10-02 13:26:35 +00003/*--- MemCheck: Maintain bitmaps of memory, tracking the ---*/
4/*--- accessibility (A) and validity (V) status of each byte. ---*/
njn25cac76cb2002-09-23 11:21:57 +00005/*--- mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00006/*--------------------------------------------------------------------*/
7
8/*
nethercote137bc552003-11-14 17:47:54 +00009 This file is part of MemCheck, a heavyweight Valgrind tool for
njnc9539842002-10-02 13:26:35 +000010 detecting memory errors.
njn25e49d8e72002-09-23 09:36:25 +000011
sewardj4d474d02008-02-11 11:34:59 +000012 Copyright (C) 2000-2008 Julian Seward
njn25e49d8e72002-09-23 09:36:25 +000013 jseward@acm.org
14
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation; either version 2 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307, USA.
29
30 The GNU General Public License is contained in the file COPYING.
31*/
32
njnc7561b92005-06-19 01:24:32 +000033#include "pub_tool_basics.h"
njn4802b382005-06-11 04:58:29 +000034#include "pub_tool_aspacemgr.h"
njn1d0825f2006-03-27 11:37:07 +000035#include "pub_tool_hashtable.h" // For mc_include.h
njn97405b22005-06-02 03:39:33 +000036#include "pub_tool_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000037#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000038#include "pub_tool_libcprint.h"
njnf536bbb2005-06-13 04:21:38 +000039#include "pub_tool_machine.h"
njnc7561b92005-06-19 01:24:32 +000040#include "pub_tool_mallocfree.h"
41#include "pub_tool_options.h"
njn1d0825f2006-03-27 11:37:07 +000042#include "pub_tool_oset.h"
njnc7561b92005-06-19 01:24:32 +000043#include "pub_tool_replacemalloc.h"
44#include "pub_tool_tooliface.h"
45#include "pub_tool_threadstate.h"
46
47#include "mc_include.h"
48#include "memcheck.h" /* for client requests */
njn25e49d8e72002-09-23 09:36:25 +000049
sewardjc1a2cda2005-04-21 17:34:00 +000050
njn1d0825f2006-03-27 11:37:07 +000051/* Set to 1 to do a little more sanity checking */
sewardj23eb2fd2005-04-22 16:29:19 +000052#define VG_DEBUG_MEMORY 0
sewardjc1a2cda2005-04-21 17:34:00 +000053
njn25e49d8e72002-09-23 09:36:25 +000054#define DEBUG(fmt, args...) //VG_(printf)(fmt, ## args)
55
sewardj7cf4e6b2008-05-01 20:24:26 +000056static void ocache_sarp_Set_Origins ( Addr, UWord, UInt ); /* fwds */
57static void ocache_sarp_Clear_Origins ( Addr, UWord ); /* fwds */
58
njn25e49d8e72002-09-23 09:36:25 +000059
njn25e49d8e72002-09-23 09:36:25 +000060/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +000061/*--- Fast-case knobs ---*/
62/*------------------------------------------------------------*/
63
64// Comment these out to disable the fast cases (don't just set them to zero).
65
66#define PERF_FAST_LOADV 1
67#define PERF_FAST_STOREV 1
68
69#define PERF_FAST_SARP 1
70
71#define PERF_FAST_STACK 1
72#define PERF_FAST_STACK2 1
73
sewardj7cf4e6b2008-05-01 20:24:26 +000074/* Change this to 1 to enable assertions on origin tracking cache fast
75 paths */
76#define OC_ENABLE_ASSERTIONS 0
77
78
njn1d0825f2006-03-27 11:37:07 +000079/*------------------------------------------------------------*/
80/*--- V bits and A bits ---*/
81/*------------------------------------------------------------*/
82
83/* Conceptually, every byte value has 8 V bits, which track whether Memcheck
84 thinks the corresponding value bit is defined. And every memory byte
85 has an A bit, which tracks whether Memcheck thinks the program can access
86 it safely. So every N-bit register is shadowed with N V bits, and every
87 memory byte is shadowed with 8 V bits and one A bit.
88
89 In the implementation, we use two forms of compression (compressed V bits
90 and distinguished secondary maps) to avoid the 9-bit-per-byte overhead
91 for memory.
92
93 Memcheck also tracks extra information about each heap block that is
94 allocated, for detecting memory leaks and other purposes.
95*/
96
97/*------------------------------------------------------------*/
sewardj45d94cc2005-04-20 14:44:11 +000098/*--- Basic A/V bitmap representation. ---*/
njn25e49d8e72002-09-23 09:36:25 +000099/*------------------------------------------------------------*/
100
njn1d0825f2006-03-27 11:37:07 +0000101/* All reads and writes are checked against a memory map (a.k.a. shadow
102 memory), which records the state of all memory in the process.
103
104 On 32-bit machines the memory map is organised as follows.
105 The top 16 bits of an address are used to index into a top-level
106 map table, containing 65536 entries. Each entry is a pointer to a
107 second-level map, which records the accesibililty and validity
108 permissions for the 65536 bytes indexed by the lower 16 bits of the
109 address. Each byte is represented by two bits (details are below). So
110 each second-level map contains 16384 bytes. This two-level arrangement
111 conveniently divides the 4G address space into 64k lumps, each size 64k
112 bytes.
113
114 All entries in the primary (top-level) map must point to a valid
115 secondary (second-level) map. Since many of the 64kB chunks will
njndbf7ca72006-03-31 11:57:59 +0000116 have the same status for every bit -- ie. noaccess (for unused
117 address space) or entirely addressable and defined (for code segments) --
118 there are three distinguished secondary maps, which indicate 'noaccess',
119 'undefined' and 'defined'. For these uniform 64kB chunks, the primary
120 map entry points to the relevant distinguished map. In practice,
121 typically more than half of the addressable memory is represented with
122 the 'undefined' or 'defined' distinguished secondary map, so it gives a
123 good saving. It also lets us set the V+A bits of large address regions
124 quickly in set_address_range_perms().
njn1d0825f2006-03-27 11:37:07 +0000125
126 On 64-bit machines it's more complicated. If we followed the same basic
127 scheme we'd have a four-level table which would require too many memory
128 accesses. So instead the top-level map table has 2^19 entries (indexed
129 using bits 16..34 of the address); this covers the bottom 32GB. Any
130 accesses above 32GB are handled with a slow, sparse auxiliary table.
131 Valgrind's address space manager tries very hard to keep things below
132 this 32GB barrier so that performance doesn't suffer too much.
133
134 Note that this file has a lot of different functions for reading and
135 writing shadow memory. Only a couple are strictly necessary (eg.
136 get_vabits2 and set_vabits2), most are just specialised for specific
137 common cases to improve performance.
138
139 Aside: the V+A bits are less precise than they could be -- we have no way
140 of marking memory as read-only. It would be great if we could add an
141 extra state VA_BITSn_READONLY. But then we'd have 5 different states,
142 which requires 2.3 bits to hold, and there's no way to do that elegantly
143 -- we'd have to double up to 4 bits of metadata per byte, which doesn't
144 seem worth it.
145*/
sewardjc859fbf2005-04-22 21:10:28 +0000146
sewardj45d94cc2005-04-20 14:44:11 +0000147/* --------------- Basic configuration --------------- */
sewardj95448072004-11-22 20:19:51 +0000148
sewardj23eb2fd2005-04-22 16:29:19 +0000149/* Only change this. N_PRIMARY_MAP *must* be a power of 2. */
sewardj21f7ff42005-04-28 10:32:02 +0000150
sewardje4ccc012005-05-02 12:53:38 +0000151#if VG_WORDSIZE == 4
sewardj21f7ff42005-04-28 10:32:02 +0000152
153/* cover the entire address space */
154# define N_PRIMARY_BITS 16
155
156#else
157
sewardj34483bc2005-09-28 11:50:20 +0000158/* Just handle the first 32G fast and the rest via auxiliary
sewardj7244e712008-05-02 12:35:48 +0000159 primaries. If you change this, Memcheck will assert at startup.
160 See the definition of UNALIGNED_OR_HIGH for extensive comments. */
sewardj34483bc2005-09-28 11:50:20 +0000161# define N_PRIMARY_BITS 19
sewardj21f7ff42005-04-28 10:32:02 +0000162
163#endif
164
sewardj45d94cc2005-04-20 14:44:11 +0000165
sewardjc1a2cda2005-04-21 17:34:00 +0000166/* Do not change this. */
sewardje4ccc012005-05-02 12:53:38 +0000167#define N_PRIMARY_MAP ( ((UWord)1) << N_PRIMARY_BITS)
sewardjc1a2cda2005-04-21 17:34:00 +0000168
169/* Do not change this. */
sewardj23eb2fd2005-04-22 16:29:19 +0000170#define MAX_PRIMARY_ADDRESS (Addr)((((Addr)65536) * N_PRIMARY_MAP)-1)
171
172
sewardj45d94cc2005-04-20 14:44:11 +0000173/* --------------- Secondary maps --------------- */
njn25e49d8e72002-09-23 09:36:25 +0000174
njn1d0825f2006-03-27 11:37:07 +0000175// Each byte of memory conceptually has an A bit, which indicates its
176// addressability, and 8 V bits, which indicates its definedness.
177//
178// But because very few bytes are partially defined, we can use a nice
179// compression scheme to reduce the size of shadow memory. Each byte of
180// memory has 2 bits which indicates its state (ie. V+A bits):
181//
njndbf7ca72006-03-31 11:57:59 +0000182// 00: noaccess (unaddressable but treated as fully defined)
183// 01: undefined (addressable and fully undefined)
184// 10: defined (addressable and fully defined)
185// 11: partdefined (addressable and partially defined)
njn1d0825f2006-03-27 11:37:07 +0000186//
njndbf7ca72006-03-31 11:57:59 +0000187// In the "partdefined" case, we use a secondary table to store the V bits.
188// Each entry in the secondary-V-bits table maps a byte address to its 8 V
189// bits.
njn1d0825f2006-03-27 11:37:07 +0000190//
191// We store the compressed V+A bits in 8-bit chunks, ie. the V+A bits for
192// four bytes (32 bits) of memory are in each chunk. Hence the name
193// "vabits8". This lets us get the V+A bits for four bytes at a time
194// easily (without having to do any shifting and/or masking), and that is a
195// very common operation. (Note that although each vabits8 chunk
196// is 8 bits in size, it represents 32 bits of memory.)
197//
198// The representation is "inverse" little-endian... each 4 bytes of
199// memory is represented by a 1 byte value, where:
200//
201// - the status of byte (a+0) is held in bits [1..0]
202// - the status of byte (a+1) is held in bits [3..2]
203// - the status of byte (a+2) is held in bits [5..4]
204// - the status of byte (a+3) is held in bits [7..6]
205//
206// It's "inverse" because endianness normally describes a mapping from
207// value bits to memory addresses; in this case the mapping is inverted.
208// Ie. instead of particular value bits being held in certain addresses, in
209// this case certain addresses are represented by particular value bits.
210// See insert_vabits2_into_vabits8() for an example.
211//
212// But note that we don't compress the V bits stored in registers; they
213// need to be explicit to made the shadow operations possible. Therefore
214// when moving values between registers and memory we need to convert
215// between the expanded in-register format and the compressed in-memory
216// format. This isn't so difficult, it just requires careful attention in a
217// few places.
218
219// These represent eight bits of memory.
220#define VA_BITS2_NOACCESS 0x0 // 00b
njndbf7ca72006-03-31 11:57:59 +0000221#define VA_BITS2_UNDEFINED 0x1 // 01b
222#define VA_BITS2_DEFINED 0x2 // 10b
223#define VA_BITS2_PARTDEFINED 0x3 // 11b
njn1d0825f2006-03-27 11:37:07 +0000224
225// These represent 16 bits of memory.
226#define VA_BITS4_NOACCESS 0x0 // 00_00b
njndbf7ca72006-03-31 11:57:59 +0000227#define VA_BITS4_UNDEFINED 0x5 // 01_01b
228#define VA_BITS4_DEFINED 0xa // 10_10b
njn1d0825f2006-03-27 11:37:07 +0000229
230// These represent 32 bits of memory.
231#define VA_BITS8_NOACCESS 0x00 // 00_00_00_00b
njndbf7ca72006-03-31 11:57:59 +0000232#define VA_BITS8_UNDEFINED 0x55 // 01_01_01_01b
233#define VA_BITS8_DEFINED 0xaa // 10_10_10_10b
njn1d0825f2006-03-27 11:37:07 +0000234
235// These represent 64 bits of memory.
236#define VA_BITS16_NOACCESS 0x0000 // 00_00_00_00b x 2
njndbf7ca72006-03-31 11:57:59 +0000237#define VA_BITS16_UNDEFINED 0x5555 // 01_01_01_01b x 2
238#define VA_BITS16_DEFINED 0xaaaa // 10_10_10_10b x 2
njn1d0825f2006-03-27 11:37:07 +0000239
240
241#define SM_CHUNKS 16384
242#define SM_OFF(aaa) (((aaa) & 0xffff) >> 2)
243#define SM_OFF_16(aaa) (((aaa) & 0xffff) >> 3)
244
245// Paranoia: it's critical for performance that the requested inlining
246// occurs. So try extra hard.
247#define INLINE inline __attribute__((always_inline))
248
249static INLINE Addr start_of_this_sm ( Addr a ) {
250 return (a & (~SM_MASK));
251}
252static INLINE Bool is_start_of_sm ( Addr a ) {
253 return (start_of_this_sm(a) == a);
254}
255
njn25e49d8e72002-09-23 09:36:25 +0000256typedef
257 struct {
njn1d0825f2006-03-27 11:37:07 +0000258 UChar vabits8[SM_CHUNKS];
njn25e49d8e72002-09-23 09:36:25 +0000259 }
260 SecMap;
261
njn1d0825f2006-03-27 11:37:07 +0000262// 3 distinguished secondary maps, one for no-access, one for
263// accessible but undefined, and one for accessible and defined.
264// Distinguished secondaries may never be modified.
265#define SM_DIST_NOACCESS 0
njndbf7ca72006-03-31 11:57:59 +0000266#define SM_DIST_UNDEFINED 1
267#define SM_DIST_DEFINED 2
njnb8dca862005-03-14 02:42:44 +0000268
sewardj45d94cc2005-04-20 14:44:11 +0000269static SecMap sm_distinguished[3];
njnb8dca862005-03-14 02:42:44 +0000270
njn1d0825f2006-03-27 11:37:07 +0000271static INLINE Bool is_distinguished_sm ( SecMap* sm ) {
sewardj45d94cc2005-04-20 14:44:11 +0000272 return sm >= &sm_distinguished[0] && sm <= &sm_distinguished[2];
273}
njnb8dca862005-03-14 02:42:44 +0000274
njn1d0825f2006-03-27 11:37:07 +0000275// Forward declaration
276static void update_SM_counts(SecMap* oldSM, SecMap* newSM);
277
sewardj45d94cc2005-04-20 14:44:11 +0000278/* dist_sm points to one of our three distinguished secondaries. Make
279 a copy of it so that we can write to it.
280*/
281static SecMap* copy_for_writing ( SecMap* dist_sm )
282{
283 SecMap* new_sm;
284 tl_assert(dist_sm == &sm_distinguished[0]
njn1d0825f2006-03-27 11:37:07 +0000285 || dist_sm == &sm_distinguished[1]
286 || dist_sm == &sm_distinguished[2]);
njnb8dca862005-03-14 02:42:44 +0000287
sewardj45f4e7c2005-09-27 19:20:21 +0000288 new_sm = VG_(am_shadow_alloc)(sizeof(SecMap));
289 if (new_sm == NULL)
290 VG_(out_of_memory_NORETURN)( "memcheck:allocate new SecMap",
291 sizeof(SecMap) );
sewardj45d94cc2005-04-20 14:44:11 +0000292 VG_(memcpy)(new_sm, dist_sm, sizeof(SecMap));
njn1d0825f2006-03-27 11:37:07 +0000293 update_SM_counts(dist_sm, new_sm);
sewardj45d94cc2005-04-20 14:44:11 +0000294 return new_sm;
295}
njnb8dca862005-03-14 02:42:44 +0000296
njn1d0825f2006-03-27 11:37:07 +0000297/* --------------- Stats --------------- */
298
njndbf7ca72006-03-31 11:57:59 +0000299static Int n_issued_SMs = 0;
300static Int n_deissued_SMs = 0;
301static Int n_noaccess_SMs = N_PRIMARY_MAP; // start with many noaccess DSMs
302static Int n_undefined_SMs = 0;
303static Int n_defined_SMs = 0;
304static Int n_non_DSM_SMs = 0;
305static Int max_noaccess_SMs = 0;
306static Int max_undefined_SMs = 0;
307static Int max_defined_SMs = 0;
308static Int max_non_DSM_SMs = 0;
njn1d0825f2006-03-27 11:37:07 +0000309
sewardj05a46732006-10-17 01:28:10 +0000310/* # searches initiated in auxmap_L1, and # base cmps required */
311static ULong n_auxmap_L1_searches = 0;
312static ULong n_auxmap_L1_cmps = 0;
313/* # of searches that missed in auxmap_L1 and therefore had to
314 be handed to auxmap_L2. And the number of nodes inserted. */
315static ULong n_auxmap_L2_searches = 0;
316static ULong n_auxmap_L2_nodes = 0;
317
njn1d0825f2006-03-27 11:37:07 +0000318static Int n_sanity_cheap = 0;
319static Int n_sanity_expensive = 0;
320
321static Int n_secVBit_nodes = 0;
322static Int max_secVBit_nodes = 0;
323
324static void update_SM_counts(SecMap* oldSM, SecMap* newSM)
325{
njndbf7ca72006-03-31 11:57:59 +0000326 if (oldSM == &sm_distinguished[SM_DIST_NOACCESS ]) n_noaccess_SMs --;
327 else if (oldSM == &sm_distinguished[SM_DIST_UNDEFINED]) n_undefined_SMs--;
328 else if (oldSM == &sm_distinguished[SM_DIST_DEFINED ]) n_defined_SMs --;
329 else { n_non_DSM_SMs --;
330 n_deissued_SMs ++; }
njn1d0825f2006-03-27 11:37:07 +0000331
njndbf7ca72006-03-31 11:57:59 +0000332 if (newSM == &sm_distinguished[SM_DIST_NOACCESS ]) n_noaccess_SMs ++;
333 else if (newSM == &sm_distinguished[SM_DIST_UNDEFINED]) n_undefined_SMs++;
334 else if (newSM == &sm_distinguished[SM_DIST_DEFINED ]) n_defined_SMs ++;
335 else { n_non_DSM_SMs ++;
336 n_issued_SMs ++; }
njn1d0825f2006-03-27 11:37:07 +0000337
njndbf7ca72006-03-31 11:57:59 +0000338 if (n_noaccess_SMs > max_noaccess_SMs ) max_noaccess_SMs = n_noaccess_SMs;
339 if (n_undefined_SMs > max_undefined_SMs) max_undefined_SMs = n_undefined_SMs;
340 if (n_defined_SMs > max_defined_SMs ) max_defined_SMs = n_defined_SMs;
341 if (n_non_DSM_SMs > max_non_DSM_SMs ) max_non_DSM_SMs = n_non_DSM_SMs;
njn1d0825f2006-03-27 11:37:07 +0000342}
sewardj45d94cc2005-04-20 14:44:11 +0000343
344/* --------------- Primary maps --------------- */
345
346/* The main primary map. This covers some initial part of the address
sewardj23eb2fd2005-04-22 16:29:19 +0000347 space, addresses 0 .. (N_PRIMARY_MAP << 16)-1. The rest of it is
sewardj45d94cc2005-04-20 14:44:11 +0000348 handled using the auxiliary primary map.
349*/
sewardj23eb2fd2005-04-22 16:29:19 +0000350static SecMap* primary_map[N_PRIMARY_MAP];
sewardj45d94cc2005-04-20 14:44:11 +0000351
352
353/* An entry in the auxiliary primary map. base must be a 64k-aligned
354 value, and sm points at the relevant secondary map. As with the
355 main primary map, the secondary may be either a real secondary, or
sewardj05a46732006-10-17 01:28:10 +0000356 one of the three distinguished secondaries. DO NOT CHANGE THIS
357 LAYOUT: the first word has to be the key for OSet fast lookups.
sewardj45d94cc2005-04-20 14:44:11 +0000358*/
359typedef
360 struct {
sewardj23eb2fd2005-04-22 16:29:19 +0000361 Addr base;
sewardj45d94cc2005-04-20 14:44:11 +0000362 SecMap* sm;
363 }
364 AuxMapEnt;
365
sewardj05a46732006-10-17 01:28:10 +0000366/* Tunable parameter: How big is the L1 queue? */
367#define N_AUXMAP_L1 24
sewardj45d94cc2005-04-20 14:44:11 +0000368
sewardj05a46732006-10-17 01:28:10 +0000369/* Tunable parameter: How far along the L1 queue to insert
370 entries resulting from L2 lookups? */
371#define AUXMAP_L1_INSERT_IX 12
sewardj45d94cc2005-04-20 14:44:11 +0000372
sewardj05a46732006-10-17 01:28:10 +0000373static struct {
374 Addr base;
375 AuxMapEnt* ent; // pointer to the matching auxmap_L2 node
376 }
377 auxmap_L1[N_AUXMAP_L1];
378
379static OSet* auxmap_L2 = NULL;
380
381static void init_auxmap_L1_L2 ( void )
sewardj45d94cc2005-04-20 14:44:11 +0000382{
sewardj05a46732006-10-17 01:28:10 +0000383 Int i;
384 for (i = 0; i < N_AUXMAP_L1; i++) {
385 auxmap_L1[i].base = 0;
386 auxmap_L1[i].ent = NULL;
sewardj45d94cc2005-04-20 14:44:11 +0000387 }
388
sewardj05a46732006-10-17 01:28:10 +0000389 tl_assert(0 == offsetof(AuxMapEnt,base));
390 tl_assert(sizeof(Addr) == sizeof(void*));
njne2a9ad32007-09-17 05:30:48 +0000391 auxmap_L2 = VG_(OSetGen_Create)( /*keyOff*/ offsetof(AuxMapEnt,base),
392 /*fastCmp*/ NULL,
393 VG_(malloc), VG_(free) );
sewardj05fe85e2005-04-27 22:46:36 +0000394}
395
sewardj05a46732006-10-17 01:28:10 +0000396/* Check representation invariants; if OK return NULL; else a
397 descriptive bit of text. Also return the number of
398 non-distinguished secondary maps referred to from the auxiliary
399 primary maps. */
sewardj05fe85e2005-04-27 22:46:36 +0000400
sewardj05a46732006-10-17 01:28:10 +0000401static HChar* check_auxmap_L1_L2_sanity ( Word* n_secmaps_found )
sewardj05fe85e2005-04-27 22:46:36 +0000402{
sewardj05a46732006-10-17 01:28:10 +0000403 Word i, j;
404 /* On a 32-bit platform, the L2 and L1 tables should
405 both remain empty forever.
sewardj05fe85e2005-04-27 22:46:36 +0000406
sewardj05a46732006-10-17 01:28:10 +0000407 On a 64-bit platform:
408 In the L2 table:
409 all .base & 0xFFFF == 0
410 all .base > MAX_PRIMARY_ADDRESS
411 In the L1 table:
412 all .base & 0xFFFF == 0
413 all (.base > MAX_PRIMARY_ADDRESS
414 .base & 0xFFFF == 0
415 and .ent points to an AuxMapEnt with the same .base)
416 or
417 (.base == 0 and .ent == NULL)
418 */
419 *n_secmaps_found = 0;
420 if (sizeof(void*) == 4) {
421 /* 32-bit platform */
njne2a9ad32007-09-17 05:30:48 +0000422 if (VG_(OSetGen_Size)(auxmap_L2) != 0)
sewardj05a46732006-10-17 01:28:10 +0000423 return "32-bit: auxmap_L2 is non-empty";
424 for (i = 0; i < N_AUXMAP_L1; i++)
425 if (auxmap_L1[i].base != 0 || auxmap_L1[i].ent != NULL)
426 return "32-bit: auxmap_L1 is non-empty";
427 } else {
428 /* 64-bit platform */
429 UWord elems_seen = 0;
430 AuxMapEnt *elem, *res;
431 AuxMapEnt key;
432 /* L2 table */
njne2a9ad32007-09-17 05:30:48 +0000433 VG_(OSetGen_ResetIter)(auxmap_L2);
434 while ( (elem = VG_(OSetGen_Next)(auxmap_L2)) ) {
sewardj05a46732006-10-17 01:28:10 +0000435 elems_seen++;
436 if (0 != (elem->base & (Addr)0xFFFF))
437 return "64-bit: nonzero .base & 0xFFFF in auxmap_L2";
438 if (elem->base <= MAX_PRIMARY_ADDRESS)
439 return "64-bit: .base <= MAX_PRIMARY_ADDRESS in auxmap_L2";
440 if (elem->sm == NULL)
441 return "64-bit: .sm in _L2 is NULL";
442 if (!is_distinguished_sm(elem->sm))
443 (*n_secmaps_found)++;
444 }
445 if (elems_seen != n_auxmap_L2_nodes)
446 return "64-bit: disagreement on number of elems in _L2";
447 /* Check L1-L2 correspondence */
448 for (i = 0; i < N_AUXMAP_L1; i++) {
449 if (auxmap_L1[i].base == 0 && auxmap_L1[i].ent == NULL)
450 continue;
451 if (0 != (auxmap_L1[i].base & (Addr)0xFFFF))
452 return "64-bit: nonzero .base & 0xFFFF in auxmap_L1";
453 if (auxmap_L1[i].base <= MAX_PRIMARY_ADDRESS)
454 return "64-bit: .base <= MAX_PRIMARY_ADDRESS in auxmap_L1";
455 if (auxmap_L1[i].ent == NULL)
456 return "64-bit: .ent is NULL in auxmap_L1";
457 if (auxmap_L1[i].ent->base != auxmap_L1[i].base)
458 return "64-bit: _L1 and _L2 bases are inconsistent";
459 /* Look it up in auxmap_L2. */
460 key.base = auxmap_L1[i].base;
461 key.sm = 0;
njne2a9ad32007-09-17 05:30:48 +0000462 res = VG_(OSetGen_Lookup)(auxmap_L2, &key);
sewardj05a46732006-10-17 01:28:10 +0000463 if (res == NULL)
464 return "64-bit: _L1 .base not found in _L2";
465 if (res != auxmap_L1[i].ent)
466 return "64-bit: _L1 .ent disagrees with _L2 entry";
467 }
468 /* Check L1 contains no duplicates */
469 for (i = 0; i < N_AUXMAP_L1; i++) {
470 if (auxmap_L1[i].base == 0)
471 continue;
472 for (j = i+1; j < N_AUXMAP_L1; j++) {
473 if (auxmap_L1[j].base == 0)
474 continue;
475 if (auxmap_L1[j].base == auxmap_L1[i].base)
476 return "64-bit: duplicate _L1 .base entries";
477 }
478 }
479 }
480 return NULL; /* ok */
481}
482
483static void insert_into_auxmap_L1_at ( Word rank, AuxMapEnt* ent )
484{
485 Word i;
486 tl_assert(ent);
487 tl_assert(rank >= 0 && rank < N_AUXMAP_L1);
488 for (i = N_AUXMAP_L1-1; i > rank; i--)
489 auxmap_L1[i] = auxmap_L1[i-1];
490 auxmap_L1[rank].base = ent->base;
491 auxmap_L1[rank].ent = ent;
492}
493
494static INLINE AuxMapEnt* maybe_find_in_auxmap ( Addr a )
495{
496 AuxMapEnt key;
497 AuxMapEnt* res;
498 Word i;
499
500 tl_assert(a > MAX_PRIMARY_ADDRESS);
501 a &= ~(Addr)0xFFFF;
502
503 /* First search the front-cache, which is a self-organising
504 list containing the most popular entries. */
505
bart5dd8e6a2008-03-22 08:04:29 +0000506 if (LIKELY(auxmap_L1[0].base == a))
sewardj05a46732006-10-17 01:28:10 +0000507 return auxmap_L1[0].ent;
bart5dd8e6a2008-03-22 08:04:29 +0000508 if (LIKELY(auxmap_L1[1].base == a)) {
sewardj05a46732006-10-17 01:28:10 +0000509 Addr t_base = auxmap_L1[0].base;
510 AuxMapEnt* t_ent = auxmap_L1[0].ent;
511 auxmap_L1[0].base = auxmap_L1[1].base;
512 auxmap_L1[0].ent = auxmap_L1[1].ent;
513 auxmap_L1[1].base = t_base;
514 auxmap_L1[1].ent = t_ent;
515 return auxmap_L1[0].ent;
sewardj45d94cc2005-04-20 14:44:11 +0000516 }
517
sewardj05a46732006-10-17 01:28:10 +0000518 n_auxmap_L1_searches++;
sewardj45d94cc2005-04-20 14:44:11 +0000519
sewardj05a46732006-10-17 01:28:10 +0000520 for (i = 0; i < N_AUXMAP_L1; i++) {
521 if (auxmap_L1[i].base == a) {
522 break;
523 }
524 }
525 tl_assert(i >= 0 && i <= N_AUXMAP_L1);
sewardj45d94cc2005-04-20 14:44:11 +0000526
sewardj05a46732006-10-17 01:28:10 +0000527 n_auxmap_L1_cmps += (ULong)(i+1);
sewardj45d94cc2005-04-20 14:44:11 +0000528
sewardj05a46732006-10-17 01:28:10 +0000529 if (i < N_AUXMAP_L1) {
530 if (i > 0) {
531 Addr t_base = auxmap_L1[i-1].base;
532 AuxMapEnt* t_ent = auxmap_L1[i-1].ent;
533 auxmap_L1[i-1].base = auxmap_L1[i-0].base;
534 auxmap_L1[i-1].ent = auxmap_L1[i-0].ent;
535 auxmap_L1[i-0].base = t_base;
536 auxmap_L1[i-0].ent = t_ent;
537 i--;
538 }
539 return auxmap_L1[i].ent;
540 }
541
542 n_auxmap_L2_searches++;
543
544 /* First see if we already have it. */
545 key.base = a;
546 key.sm = 0;
547
njne2a9ad32007-09-17 05:30:48 +0000548 res = VG_(OSetGen_Lookup)(auxmap_L2, &key);
sewardj05a46732006-10-17 01:28:10 +0000549 if (res)
550 insert_into_auxmap_L1_at( AUXMAP_L1_INSERT_IX, res );
551 return res;
552}
553
554static AuxMapEnt* find_or_alloc_in_auxmap ( Addr a )
555{
556 AuxMapEnt *nyu, *res;
557
558 /* First see if we already have it. */
559 res = maybe_find_in_auxmap( a );
bart5dd8e6a2008-03-22 08:04:29 +0000560 if (LIKELY(res))
sewardj05a46732006-10-17 01:28:10 +0000561 return res;
562
563 /* Ok, there's no entry in the secondary map, so we'll have
564 to allocate one. */
565 a &= ~(Addr)0xFFFF;
566
njne2a9ad32007-09-17 05:30:48 +0000567 nyu = (AuxMapEnt*) VG_(OSetGen_AllocNode)( auxmap_L2, sizeof(AuxMapEnt) );
sewardj05a46732006-10-17 01:28:10 +0000568 tl_assert(nyu);
569 nyu->base = a;
570 nyu->sm = &sm_distinguished[SM_DIST_NOACCESS];
njne2a9ad32007-09-17 05:30:48 +0000571 VG_(OSetGen_Insert)( auxmap_L2, nyu );
sewardj05a46732006-10-17 01:28:10 +0000572 insert_into_auxmap_L1_at( AUXMAP_L1_INSERT_IX, nyu );
573 n_auxmap_L2_nodes++;
574 return nyu;
sewardj45d94cc2005-04-20 14:44:11 +0000575}
576
sewardj45d94cc2005-04-20 14:44:11 +0000577/* --------------- SecMap fundamentals --------------- */
578
njn1d0825f2006-03-27 11:37:07 +0000579// In all these, 'low' means it's definitely in the main primary map,
580// 'high' means it's definitely in the auxiliary table.
581
582static INLINE SecMap** get_secmap_low_ptr ( Addr a )
583{
584 UWord pm_off = a >> 16;
585# if VG_DEBUG_MEMORY >= 1
586 tl_assert(pm_off < N_PRIMARY_MAP);
587# endif
588 return &primary_map[ pm_off ];
589}
590
591static INLINE SecMap** get_secmap_high_ptr ( Addr a )
592{
593 AuxMapEnt* am = find_or_alloc_in_auxmap(a);
594 return &am->sm;
595}
596
597static SecMap** get_secmap_ptr ( Addr a )
598{
599 return ( a <= MAX_PRIMARY_ADDRESS
600 ? get_secmap_low_ptr(a)
601 : get_secmap_high_ptr(a));
602}
603
njna7c7ebd2006-03-28 12:51:02 +0000604static INLINE SecMap* get_secmap_for_reading_low ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000605{
606 return *get_secmap_low_ptr(a);
607}
608
njna7c7ebd2006-03-28 12:51:02 +0000609static INLINE SecMap* get_secmap_for_reading_high ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000610{
611 return *get_secmap_high_ptr(a);
612}
613
njna7c7ebd2006-03-28 12:51:02 +0000614static INLINE SecMap* get_secmap_for_writing_low(Addr a)
njn1d0825f2006-03-27 11:37:07 +0000615{
616 SecMap** p = get_secmap_low_ptr(a);
bart5dd8e6a2008-03-22 08:04:29 +0000617 if (UNLIKELY(is_distinguished_sm(*p)))
njn1d0825f2006-03-27 11:37:07 +0000618 *p = copy_for_writing(*p);
619 return *p;
620}
621
njna7c7ebd2006-03-28 12:51:02 +0000622static INLINE SecMap* get_secmap_for_writing_high ( Addr a )
njn1d0825f2006-03-27 11:37:07 +0000623{
624 SecMap** p = get_secmap_high_ptr(a);
bart5dd8e6a2008-03-22 08:04:29 +0000625 if (UNLIKELY(is_distinguished_sm(*p)))
njn1d0825f2006-03-27 11:37:07 +0000626 *p = copy_for_writing(*p);
627 return *p;
628}
629
sewardj45d94cc2005-04-20 14:44:11 +0000630/* Produce the secmap for 'a', either from the primary map or by
631 ensuring there is an entry for it in the aux primary map. The
632 secmap may be a distinguished one as the caller will only want to
633 be able to read it.
634*/
sewardj05a46732006-10-17 01:28:10 +0000635static INLINE SecMap* get_secmap_for_reading ( Addr a )
sewardj45d94cc2005-04-20 14:44:11 +0000636{
njn1d0825f2006-03-27 11:37:07 +0000637 return ( a <= MAX_PRIMARY_ADDRESS
njna7c7ebd2006-03-28 12:51:02 +0000638 ? get_secmap_for_reading_low (a)
639 : get_secmap_for_reading_high(a) );
sewardj45d94cc2005-04-20 14:44:11 +0000640}
641
642/* Produce the secmap for 'a', either from the primary map or by
643 ensuring there is an entry for it in the aux primary map. The
644 secmap may not be a distinguished one, since the caller will want
645 to be able to write it. If it is a distinguished secondary, make a
646 writable copy of it, install it, and return the copy instead. (COW
647 semantics).
648*/
njna7c7ebd2006-03-28 12:51:02 +0000649static SecMap* get_secmap_for_writing ( Addr a )
sewardj45d94cc2005-04-20 14:44:11 +0000650{
njn1d0825f2006-03-27 11:37:07 +0000651 return ( a <= MAX_PRIMARY_ADDRESS
njna7c7ebd2006-03-28 12:51:02 +0000652 ? get_secmap_for_writing_low (a)
653 : get_secmap_for_writing_high(a) );
njn1d0825f2006-03-27 11:37:07 +0000654}
655
656/* If 'a' has a SecMap, produce it. Else produce NULL. But don't
657 allocate one if one doesn't already exist. This is used by the
658 leak checker.
659*/
660static SecMap* maybe_get_secmap_for ( Addr a )
661{
sewardj45d94cc2005-04-20 14:44:11 +0000662 if (a <= MAX_PRIMARY_ADDRESS) {
njna7c7ebd2006-03-28 12:51:02 +0000663 return get_secmap_for_reading_low(a);
sewardj45d94cc2005-04-20 14:44:11 +0000664 } else {
njn1d0825f2006-03-27 11:37:07 +0000665 AuxMapEnt* am = maybe_find_in_auxmap(a);
666 return am ? am->sm : NULL;
sewardj45d94cc2005-04-20 14:44:11 +0000667 }
668}
669
njn1d0825f2006-03-27 11:37:07 +0000670/* --------------- Fundamental functions --------------- */
671
672static INLINE
673void insert_vabits2_into_vabits8 ( Addr a, UChar vabits2, UChar* vabits8 )
674{
675 UInt shift = (a & 3) << 1; // shift by 0, 2, 4, or 6
676 *vabits8 &= ~(0x3 << shift); // mask out the two old bits
677 *vabits8 |= (vabits2 << shift); // mask in the two new bits
678}
679
680static INLINE
681void insert_vabits4_into_vabits8 ( Addr a, UChar vabits4, UChar* vabits8 )
682{
683 UInt shift;
684 tl_assert(VG_IS_2_ALIGNED(a)); // Must be 2-aligned
685 shift = (a & 2) << 1; // shift by 0 or 4
686 *vabits8 &= ~(0xf << shift); // mask out the four old bits
687 *vabits8 |= (vabits4 << shift); // mask in the four new bits
688}
689
690static INLINE
691UChar extract_vabits2_from_vabits8 ( Addr a, UChar vabits8 )
692{
693 UInt shift = (a & 3) << 1; // shift by 0, 2, 4, or 6
694 vabits8 >>= shift; // shift the two bits to the bottom
695 return 0x3 & vabits8; // mask out the rest
696}
697
698static INLINE
699UChar extract_vabits4_from_vabits8 ( Addr a, UChar vabits8 )
700{
701 UInt shift;
702 tl_assert(VG_IS_2_ALIGNED(a)); // Must be 2-aligned
703 shift = (a & 2) << 1; // shift by 0 or 4
704 vabits8 >>= shift; // shift the four bits to the bottom
705 return 0xf & vabits8; // mask out the rest
706}
707
708// Note that these four are only used in slow cases. The fast cases do
709// clever things like combine the auxmap check (in
710// get_secmap_{read,writ}able) with alignment checks.
711
712// *** WARNING! ***
713// Any time this function is called, if it is possible that vabits2
njndbf7ca72006-03-31 11:57:59 +0000714// is equal to VA_BITS2_PARTDEFINED, then the corresponding entry in the
njn1d0825f2006-03-27 11:37:07 +0000715// sec-V-bits table must also be set!
716static INLINE
717void set_vabits2 ( Addr a, UChar vabits2 )
718{
njna7c7ebd2006-03-28 12:51:02 +0000719 SecMap* sm = get_secmap_for_writing(a);
njn1d0825f2006-03-27 11:37:07 +0000720 UWord sm_off = SM_OFF(a);
721 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
722}
723
724static INLINE
725UChar get_vabits2 ( Addr a )
726{
njna7c7ebd2006-03-28 12:51:02 +0000727 SecMap* sm = get_secmap_for_reading(a);
njn1d0825f2006-03-27 11:37:07 +0000728 UWord sm_off = SM_OFF(a);
729 UChar vabits8 = sm->vabits8[sm_off];
730 return extract_vabits2_from_vabits8(a, vabits8);
731}
732
sewardjf2184912006-05-03 22:13:57 +0000733// *** WARNING! ***
734// Any time this function is called, if it is possible that any of the
735// 4 2-bit fields in vabits8 are equal to VA_BITS2_PARTDEFINED, then the
736// corresponding entry(s) in the sec-V-bits table must also be set!
737static INLINE
738UChar get_vabits8_for_aligned_word32 ( Addr a )
739{
740 SecMap* sm = get_secmap_for_reading(a);
741 UWord sm_off = SM_OFF(a);
742 UChar vabits8 = sm->vabits8[sm_off];
743 return vabits8;
744}
745
746static INLINE
747void set_vabits8_for_aligned_word32 ( Addr a, UChar vabits8 )
748{
749 SecMap* sm = get_secmap_for_writing(a);
750 UWord sm_off = SM_OFF(a);
751 sm->vabits8[sm_off] = vabits8;
752}
753
754
njn1d0825f2006-03-27 11:37:07 +0000755// Forward declarations
756static UWord get_sec_vbits8(Addr a);
757static void set_sec_vbits8(Addr a, UWord vbits8);
758
759// Returns False if there was an addressability error.
760static INLINE
761Bool set_vbits8 ( Addr a, UChar vbits8 )
762{
763 Bool ok = True;
764 UChar vabits2 = get_vabits2(a);
765 if ( VA_BITS2_NOACCESS != vabits2 ) {
766 // Addressable. Convert in-register format to in-memory format.
767 // Also remove any existing sec V bit entry for the byte if no
768 // longer necessary.
njndbf7ca72006-03-31 11:57:59 +0000769 if ( V_BITS8_DEFINED == vbits8 ) { vabits2 = VA_BITS2_DEFINED; }
770 else if ( V_BITS8_UNDEFINED == vbits8 ) { vabits2 = VA_BITS2_UNDEFINED; }
771 else { vabits2 = VA_BITS2_PARTDEFINED;
njn1d0825f2006-03-27 11:37:07 +0000772 set_sec_vbits8(a, vbits8); }
773 set_vabits2(a, vabits2);
774
775 } else {
776 // Unaddressable! Do nothing -- when writing to unaddressable
777 // memory it acts as a black hole, and the V bits can never be seen
778 // again. So we don't have to write them at all.
779 ok = False;
780 }
781 return ok;
782}
783
784// Returns False if there was an addressability error. In that case, we put
785// all defined bits into vbits8.
786static INLINE
787Bool get_vbits8 ( Addr a, UChar* vbits8 )
788{
789 Bool ok = True;
790 UChar vabits2 = get_vabits2(a);
791
792 // Convert the in-memory format to in-register format.
njndbf7ca72006-03-31 11:57:59 +0000793 if ( VA_BITS2_DEFINED == vabits2 ) { *vbits8 = V_BITS8_DEFINED; }
794 else if ( VA_BITS2_UNDEFINED == vabits2 ) { *vbits8 = V_BITS8_UNDEFINED; }
795 else if ( VA_BITS2_NOACCESS == vabits2 ) {
njn1d0825f2006-03-27 11:37:07 +0000796 *vbits8 = V_BITS8_DEFINED; // Make V bits defined!
797 ok = False;
798 } else {
njndbf7ca72006-03-31 11:57:59 +0000799 tl_assert( VA_BITS2_PARTDEFINED == vabits2 );
njn1d0825f2006-03-27 11:37:07 +0000800 *vbits8 = get_sec_vbits8(a);
801 }
802 return ok;
803}
804
805
806/* --------------- Secondary V bit table ------------ */
807
808// This table holds the full V bit pattern for partially-defined bytes
njndbf7ca72006-03-31 11:57:59 +0000809// (PDBs) that are represented by VA_BITS2_PARTDEFINED in the main shadow
810// memory.
njn1d0825f2006-03-27 11:37:07 +0000811//
812// Note: the nodes in this table can become stale. Eg. if you write a PDB,
813// then overwrite the same address with a fully defined byte, the sec-V-bit
814// node will not necessarily be removed. This is because checking for
815// whether removal is necessary would slow down the fast paths.
816//
817// To avoid the stale nodes building up too much, we periodically (once the
818// table reaches a certain size) garbage collect (GC) the table by
819// traversing it and evicting any "sufficiently stale" nodes, ie. nodes that
820// are stale and haven't been touched for a certain number of collections.
821// If more than a certain proportion of nodes survived, we increase the
822// table size so that GCs occur less often.
823//
824// (So this a bit different to a traditional GC, where you definitely want
825// to remove any dead nodes. It's more like we have a resizable cache and
826// we're trying to find the right balance how many elements to evict and how
827// big to make the cache.)
828//
829// This policy is designed to avoid bad table bloat in the worst case where
830// a program creates huge numbers of stale PDBs -- we would get this bloat
831// if we had no GC -- while handling well the case where a node becomes
832// stale but shortly afterwards is rewritten with a PDB and so becomes
833// non-stale again (which happens quite often, eg. in perf/bz2). If we just
834// remove all stale nodes as soon as possible, we just end up re-adding a
835// lot of them in later again. The "sufficiently stale" approach avoids
836// this. (If a program has many live PDBs, performance will just suck,
837// there's no way around that.)
838
839static OSet* secVBitTable;
840
841// Stats
842static ULong sec_vbits_new_nodes = 0;
843static ULong sec_vbits_updates = 0;
844
845// This must be a power of two; this is checked in mc_pre_clo_init().
846// The size chosen here is a trade-off: if the nodes are bigger (ie. cover
847// a larger address range) they take more space but we can get multiple
848// partially-defined bytes in one if they are close to each other, reducing
849// the number of total nodes. In practice sometimes they are clustered (eg.
850// perf/bz2 repeatedly writes then reads more than 20,000 in a contiguous
851// row), but often not. So we choose something intermediate.
852#define BYTES_PER_SEC_VBIT_NODE 16
853
854// We make the table bigger if more than this many nodes survive a GC.
855#define MAX_SURVIVOR_PROPORTION 0.5
856
857// Each time we make the table bigger, we increase it by this much.
858#define TABLE_GROWTH_FACTOR 2
859
860// This defines "sufficiently stale" -- any node that hasn't been touched in
861// this many GCs will be removed.
862#define MAX_STALE_AGE 2
863
864// We GC the table when it gets this many nodes in it, ie. it's effectively
865// the table size. It can change.
866static Int secVBitLimit = 1024;
867
868// The number of GCs done, used to age sec-V-bit nodes for eviction.
869// Because it's unsigned, wrapping doesn't matter -- the right answer will
870// come out anyway.
871static UInt GCs_done = 0;
872
873typedef
874 struct {
875 Addr a;
876 UChar vbits8[BYTES_PER_SEC_VBIT_NODE];
877 UInt last_touched;
878 }
879 SecVBitNode;
880
881static OSet* createSecVBitTable(void)
882{
njne2a9ad32007-09-17 05:30:48 +0000883 return VG_(OSetGen_Create)( offsetof(SecVBitNode, a),
884 NULL, // use fast comparisons
885 VG_(malloc), VG_(free) );
njn1d0825f2006-03-27 11:37:07 +0000886}
887
888static void gcSecVBitTable(void)
889{
890 OSet* secVBitTable2;
891 SecVBitNode* n;
892 Int i, n_nodes = 0, n_survivors = 0;
893
894 GCs_done++;
895
896 // Create the new table.
897 secVBitTable2 = createSecVBitTable();
898
899 // Traverse the table, moving fresh nodes into the new table.
njne2a9ad32007-09-17 05:30:48 +0000900 VG_(OSetGen_ResetIter)(secVBitTable);
901 while ( (n = VG_(OSetGen_Next)(secVBitTable)) ) {
njn1d0825f2006-03-27 11:37:07 +0000902 Bool keep = False;
903 if ( (GCs_done - n->last_touched) <= MAX_STALE_AGE ) {
904 // Keep node if it's been touched recently enough (regardless of
905 // freshness/staleness).
906 keep = True;
907 } else {
908 // Keep node if any of its bytes are non-stale. Using
909 // get_vabits2() for the lookup is not very efficient, but I don't
910 // think it matters.
911 for (i = 0; i < BYTES_PER_SEC_VBIT_NODE; i++) {
njndbf7ca72006-03-31 11:57:59 +0000912 if (VA_BITS2_PARTDEFINED == get_vabits2(n->a + i)) {
njn1d0825f2006-03-27 11:37:07 +0000913 keep = True; // Found a non-stale byte, so keep
914 break;
915 }
916 }
917 }
918
919 if ( keep ) {
920 // Insert a copy of the node into the new table.
921 SecVBitNode* n2 =
njne2a9ad32007-09-17 05:30:48 +0000922 VG_(OSetGen_AllocNode)(secVBitTable2, sizeof(SecVBitNode));
njn1d0825f2006-03-27 11:37:07 +0000923 *n2 = *n;
njne2a9ad32007-09-17 05:30:48 +0000924 VG_(OSetGen_Insert)(secVBitTable2, n2);
njn1d0825f2006-03-27 11:37:07 +0000925 }
926 }
927
928 // Get the before and after sizes.
njne2a9ad32007-09-17 05:30:48 +0000929 n_nodes = VG_(OSetGen_Size)(secVBitTable);
930 n_survivors = VG_(OSetGen_Size)(secVBitTable2);
njn1d0825f2006-03-27 11:37:07 +0000931
932 // Destroy the old table, and put the new one in its place.
njne2a9ad32007-09-17 05:30:48 +0000933 VG_(OSetGen_Destroy)(secVBitTable);
njn1d0825f2006-03-27 11:37:07 +0000934 secVBitTable = secVBitTable2;
935
936 if (VG_(clo_verbosity) > 1) {
937 Char percbuf[6];
938 VG_(percentify)(n_survivors, n_nodes, 1, 6, percbuf);
939 VG_(message)(Vg_DebugMsg, "memcheck GC: %d nodes, %d survivors (%s)",
940 n_nodes, n_survivors, percbuf);
941 }
942
943 // Increase table size if necessary.
944 if (n_survivors > (secVBitLimit * MAX_SURVIVOR_PROPORTION)) {
945 secVBitLimit *= TABLE_GROWTH_FACTOR;
946 if (VG_(clo_verbosity) > 1)
947 VG_(message)(Vg_DebugMsg, "memcheck GC: increase table size to %d",
948 secVBitLimit);
949 }
950}
951
952static UWord get_sec_vbits8(Addr a)
953{
954 Addr aAligned = VG_ROUNDDN(a, BYTES_PER_SEC_VBIT_NODE);
955 Int amod = a % BYTES_PER_SEC_VBIT_NODE;
njne2a9ad32007-09-17 05:30:48 +0000956 SecVBitNode* n = VG_(OSetGen_Lookup)(secVBitTable, &aAligned);
njn1d0825f2006-03-27 11:37:07 +0000957 UChar vbits8;
958 tl_assert2(n, "get_sec_vbits8: no node for address %p (%p)\n", aAligned, a);
959 // Shouldn't be fully defined or fully undefined -- those cases shouldn't
960 // make it to the secondary V bits table.
961 vbits8 = n->vbits8[amod];
962 tl_assert(V_BITS8_DEFINED != vbits8 && V_BITS8_UNDEFINED != vbits8);
963 return vbits8;
964}
965
966static void set_sec_vbits8(Addr a, UWord vbits8)
967{
968 Addr aAligned = VG_ROUNDDN(a, BYTES_PER_SEC_VBIT_NODE);
969 Int i, amod = a % BYTES_PER_SEC_VBIT_NODE;
njne2a9ad32007-09-17 05:30:48 +0000970 SecVBitNode* n = VG_(OSetGen_Lookup)(secVBitTable, &aAligned);
njn1d0825f2006-03-27 11:37:07 +0000971 // Shouldn't be fully defined or fully undefined -- those cases shouldn't
972 // make it to the secondary V bits table.
973 tl_assert(V_BITS8_DEFINED != vbits8 && V_BITS8_UNDEFINED != vbits8);
974 if (n) {
975 n->vbits8[amod] = vbits8; // update
976 n->last_touched = GCs_done;
977 sec_vbits_updates++;
978 } else {
979 // New node: assign the specific byte, make the rest invalid (they
980 // should never be read as-is, but be cautious).
njne2a9ad32007-09-17 05:30:48 +0000981 n = VG_(OSetGen_AllocNode)(secVBitTable, sizeof(SecVBitNode));
njn1d0825f2006-03-27 11:37:07 +0000982 n->a = aAligned;
983 for (i = 0; i < BYTES_PER_SEC_VBIT_NODE; i++) {
984 n->vbits8[i] = V_BITS8_UNDEFINED;
985 }
986 n->vbits8[amod] = vbits8;
987 n->last_touched = GCs_done;
988
989 // Do a table GC if necessary. Nb: do this before inserting the new
990 // node, to avoid erroneously GC'ing the new node.
njne2a9ad32007-09-17 05:30:48 +0000991 if (secVBitLimit == VG_(OSetGen_Size)(secVBitTable)) {
njn1d0825f2006-03-27 11:37:07 +0000992 gcSecVBitTable();
993 }
994
995 // Insert the new node.
njne2a9ad32007-09-17 05:30:48 +0000996 VG_(OSetGen_Insert)(secVBitTable, n);
njn1d0825f2006-03-27 11:37:07 +0000997 sec_vbits_new_nodes++;
998
njne2a9ad32007-09-17 05:30:48 +0000999 n_secVBit_nodes = VG_(OSetGen_Size)(secVBitTable);
njn1d0825f2006-03-27 11:37:07 +00001000 if (n_secVBit_nodes > max_secVBit_nodes)
1001 max_secVBit_nodes = n_secVBit_nodes;
1002 }
1003}
sewardj45d94cc2005-04-20 14:44:11 +00001004
1005/* --------------- Endianness helpers --------------- */
1006
1007/* Returns the offset in memory of the byteno-th most significant byte
1008 in a wordszB-sized word, given the specified endianness. */
njn1d0825f2006-03-27 11:37:07 +00001009static INLINE UWord byte_offset_w ( UWord wordszB, Bool bigendian,
sewardj45d94cc2005-04-20 14:44:11 +00001010 UWord byteno ) {
1011 return bigendian ? (wordszB-1-byteno) : byteno;
1012}
1013
sewardj05a46732006-10-17 01:28:10 +00001014
1015/* --------------- Ignored address ranges --------------- */
1016
1017#define M_IGNORE_RANGES 4
1018
1019typedef
1020 struct {
1021 Int used;
1022 Addr start[M_IGNORE_RANGES];
1023 Addr end[M_IGNORE_RANGES];
1024 }
1025 IgnoreRanges;
1026
1027static IgnoreRanges ignoreRanges;
1028
sewardj7ce71662008-05-02 10:33:15 +00001029INLINE Bool MC_(in_ignored_range) ( Addr a )
sewardj05a46732006-10-17 01:28:10 +00001030{
1031 Int i;
bart5dd8e6a2008-03-22 08:04:29 +00001032 if (LIKELY(ignoreRanges.used == 0))
sewardj05a46732006-10-17 01:28:10 +00001033 return False;
1034 for (i = 0; i < ignoreRanges.used; i++) {
1035 if (a >= ignoreRanges.start[i] && a < ignoreRanges.end[i])
1036 return True;
1037 }
1038 return False;
1039}
1040
1041
1042/* Parse a 32- or 64-bit hex number, including leading 0x, from string
1043 starting at *ppc, putting result in *result, and return True. Or
1044 fail, in which case *ppc and *result are undefined, and return
1045 False. */
1046
1047static Bool isHex ( UChar c )
1048{
1049 return ((c >= '0' && c <= '9')
1050 || (c >= 'a' && c <= 'f')
1051 || (c >= 'A' && c <= 'F'));
1052}
1053
1054static UInt fromHex ( UChar c )
1055{
1056 if (c >= '0' && c <= '9')
1057 return (UInt)c - (UInt)'0';
1058 if (c >= 'a' && c <= 'f')
1059 return 10 + (UInt)c - (UInt)'a';
1060 if (c >= 'A' && c <= 'F')
1061 return 10 + (UInt)c - (UInt)'A';
1062 /*NOTREACHED*/
1063 tl_assert(0);
1064 return 0;
1065}
1066
1067static Bool parse_Addr ( UChar** ppc, Addr* result )
1068{
1069 Int used, limit = 2 * sizeof(Addr);
1070 if (**ppc != '0')
1071 return False;
1072 (*ppc)++;
1073 if (**ppc != 'x')
1074 return False;
1075 (*ppc)++;
1076 *result = 0;
1077 used = 0;
1078 while (isHex(**ppc)) {
1079 UInt d = fromHex(**ppc);
1080 tl_assert(d < 16);
1081 *result = ((*result) << 4) | fromHex(**ppc);
1082 (*ppc)++;
1083 used++;
1084 if (used > limit) return False;
1085 }
1086 if (used == 0)
1087 return False;
1088 return True;
1089}
1090
1091/* Parse two such numbers separated by a dash, or fail. */
1092
1093static Bool parse_range ( UChar** ppc, Addr* result1, Addr* result2 )
1094{
1095 Bool ok = parse_Addr(ppc, result1);
1096 if (!ok)
1097 return False;
1098 if (**ppc != '-')
1099 return False;
1100 (*ppc)++;
1101 ok = parse_Addr(ppc, result2);
1102 if (!ok)
1103 return False;
1104 return True;
1105}
1106
1107/* Parse a set of ranges separated by commas into 'ignoreRanges', or
1108 fail. */
1109
1110static Bool parse_ignore_ranges ( UChar* str0 )
1111{
1112 Addr start, end;
1113 Bool ok;
1114 UChar* str = str0;
1115 UChar** ppc = &str;
1116 ignoreRanges.used = 0;
1117 while (1) {
1118 ok = parse_range(ppc, &start, &end);
1119 if (!ok)
1120 return False;
1121 if (ignoreRanges.used >= M_IGNORE_RANGES)
1122 return False;
1123 ignoreRanges.start[ignoreRanges.used] = start;
1124 ignoreRanges.end[ignoreRanges.used] = end;
1125 ignoreRanges.used++;
1126 if (**ppc == 0)
1127 return True;
1128 if (**ppc != ',')
1129 return False;
1130 (*ppc)++;
1131 }
1132 /*NOTREACHED*/
1133 return False;
1134}
1135
1136
sewardj45d94cc2005-04-20 14:44:11 +00001137/* --------------- Load/store slow cases. --------------- */
1138
1139static
njn1d0825f2006-03-27 11:37:07 +00001140#ifndef PERF_FAST_LOADV
1141INLINE
1142#endif
njn45e81252006-03-28 12:35:08 +00001143ULong mc_LOADVn_slow ( Addr a, SizeT nBits, Bool bigendian )
sewardj45d94cc2005-04-20 14:44:11 +00001144{
njn1d0825f2006-03-27 11:37:07 +00001145 /* Make up a 64-bit result V word, which contains the loaded data for
sewardjf3d57dd2005-04-22 20:23:27 +00001146 valid addresses and Defined for invalid addresses. Iterate over
1147 the bytes in the word, from the most significant down to the
1148 least. */
njn1d0825f2006-03-27 11:37:07 +00001149 ULong vbits64 = V_BITS64_UNDEFINED;
njn45e81252006-03-28 12:35:08 +00001150 SizeT szB = nBits / 8;
njn1d0825f2006-03-27 11:37:07 +00001151 SSizeT i = szB-1; // Must be signed
sewardj45d94cc2005-04-20 14:44:11 +00001152 SizeT n_addrs_bad = 0;
1153 Addr ai;
njn1d0825f2006-03-27 11:37:07 +00001154 Bool partial_load_exemption_applies;
1155 UChar vbits8;
1156 Bool ok;
sewardj45d94cc2005-04-20 14:44:11 +00001157
sewardjc1a2cda2005-04-21 17:34:00 +00001158 PROF_EVENT(30, "mc_LOADVn_slow");
sewardj05a46732006-10-17 01:28:10 +00001159
1160 /* ------------ BEGIN semi-fast cases ------------ */
1161 /* These deal quickly-ish with the common auxiliary primary map
1162 cases on 64-bit platforms. Are merely a speedup hack; can be
1163 omitted without loss of correctness/functionality. Note that in
1164 both cases the "sizeof(void*) == 8" causes these cases to be
1165 folded out by compilers on 32-bit platforms. These are derived
1166 from LOADV64 and LOADV32.
1167 */
bart5dd8e6a2008-03-22 08:04:29 +00001168 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001169 && nBits == 64 && VG_IS_8_ALIGNED(a))) {
1170 SecMap* sm = get_secmap_for_reading(a);
1171 UWord sm_off16 = SM_OFF_16(a);
1172 UWord vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
bart5dd8e6a2008-03-22 08:04:29 +00001173 if (LIKELY(vabits16 == VA_BITS16_DEFINED))
sewardj05a46732006-10-17 01:28:10 +00001174 return V_BITS64_DEFINED;
bart5dd8e6a2008-03-22 08:04:29 +00001175 if (LIKELY(vabits16 == VA_BITS16_UNDEFINED))
sewardj05a46732006-10-17 01:28:10 +00001176 return V_BITS64_UNDEFINED;
1177 /* else fall into the slow case */
1178 }
bart5dd8e6a2008-03-22 08:04:29 +00001179 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001180 && nBits == 32 && VG_IS_4_ALIGNED(a))) {
1181 SecMap* sm = get_secmap_for_reading(a);
1182 UWord sm_off = SM_OFF(a);
1183 UWord vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00001184 if (LIKELY(vabits8 == VA_BITS8_DEFINED))
sewardj05a46732006-10-17 01:28:10 +00001185 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
bart5dd8e6a2008-03-22 08:04:29 +00001186 if (LIKELY(vabits8 == VA_BITS8_UNDEFINED))
sewardj05a46732006-10-17 01:28:10 +00001187 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
1188 /* else fall into slow case */
1189 }
1190 /* ------------ END semi-fast cases ------------ */
1191
njn45e81252006-03-28 12:35:08 +00001192 tl_assert(nBits == 64 || nBits == 32 || nBits == 16 || nBits == 8);
sewardj45d94cc2005-04-20 14:44:11 +00001193
njn1d0825f2006-03-27 11:37:07 +00001194 for (i = szB-1; i >= 0; i--) {
sewardjc1a2cda2005-04-21 17:34:00 +00001195 PROF_EVENT(31, "mc_LOADVn_slow(loop)");
njn45e81252006-03-28 12:35:08 +00001196 ai = a + byte_offset_w(szB, bigendian, i);
njn1d0825f2006-03-27 11:37:07 +00001197 ok = get_vbits8(ai, &vbits8);
1198 if (!ok) n_addrs_bad++;
1199 vbits64 <<= 8;
1200 vbits64 |= vbits8;
sewardj45d94cc2005-04-20 14:44:11 +00001201 }
1202
sewardj0ded7a42005-11-08 02:25:37 +00001203 /* This is a hack which avoids producing errors for code which
1204 insists in stepping along byte strings in aligned word-sized
1205 chunks, and there is a partially defined word at the end. (eg,
1206 optimised strlen). Such code is basically broken at least WRT
1207 semantics of ANSI C, but sometimes users don't have the option
1208 to fix it, and so this option is provided. Note it is now
1209 defaulted to not-engaged.
1210
1211 A load from a partially-addressible place is allowed if:
1212 - the command-line flag is set
1213 - it's a word-sized, word-aligned load
1214 - at least one of the addresses in the word *is* valid
1215 */
1216 partial_load_exemption_applies
njn1d0825f2006-03-27 11:37:07 +00001217 = MC_(clo_partial_loads_ok) && szB == VG_WORDSIZE
sewardj0ded7a42005-11-08 02:25:37 +00001218 && VG_IS_WORD_ALIGNED(a)
1219 && n_addrs_bad < VG_WORDSIZE;
1220
1221 if (n_addrs_bad > 0 && !partial_load_exemption_applies)
sewardj7ce71662008-05-02 10:33:15 +00001222 MC_(record_address_error)( VG_(get_running_tid)(), a, szB, False );
sewardj45d94cc2005-04-20 14:44:11 +00001223
njn1d0825f2006-03-27 11:37:07 +00001224 return vbits64;
sewardj45d94cc2005-04-20 14:44:11 +00001225}
1226
1227
njn1d0825f2006-03-27 11:37:07 +00001228static
1229#ifndef PERF_FAST_STOREV
1230INLINE
1231#endif
njn45e81252006-03-28 12:35:08 +00001232void mc_STOREVn_slow ( Addr a, SizeT nBits, ULong vbytes, Bool bigendian )
sewardj45d94cc2005-04-20 14:44:11 +00001233{
njn45e81252006-03-28 12:35:08 +00001234 SizeT szB = nBits / 8;
njn1d0825f2006-03-27 11:37:07 +00001235 SizeT i, n_addrs_bad = 0;
1236 UChar vbits8;
sewardj45d94cc2005-04-20 14:44:11 +00001237 Addr ai;
njn1d0825f2006-03-27 11:37:07 +00001238 Bool ok;
sewardj45d94cc2005-04-20 14:44:11 +00001239
sewardjc1a2cda2005-04-21 17:34:00 +00001240 PROF_EVENT(35, "mc_STOREVn_slow");
sewardj05a46732006-10-17 01:28:10 +00001241
1242 /* ------------ BEGIN semi-fast cases ------------ */
1243 /* These deal quickly-ish with the common auxiliary primary map
1244 cases on 64-bit platforms. Are merely a speedup hack; can be
1245 omitted without loss of correctness/functionality. Note that in
1246 both cases the "sizeof(void*) == 8" causes these cases to be
1247 folded out by compilers on 32-bit platforms. These are derived
1248 from STOREV64 and STOREV32.
1249 */
bart5dd8e6a2008-03-22 08:04:29 +00001250 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001251 && nBits == 64 && VG_IS_8_ALIGNED(a))) {
1252 SecMap* sm = get_secmap_for_reading(a);
1253 UWord sm_off16 = SM_OFF_16(a);
1254 UWord vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
bart5dd8e6a2008-03-22 08:04:29 +00001255 if (LIKELY( !is_distinguished_sm(sm) &&
sewardj05a46732006-10-17 01:28:10 +00001256 (VA_BITS16_DEFINED == vabits16 ||
1257 VA_BITS16_UNDEFINED == vabits16) )) {
1258 /* Handle common case quickly: a is suitably aligned, */
1259 /* is mapped, and is addressible. */
1260 // Convert full V-bits in register to compact 2-bit form.
bart5dd8e6a2008-03-22 08:04:29 +00001261 if (LIKELY(V_BITS64_DEFINED == vbytes)) {
sewardj05a46732006-10-17 01:28:10 +00001262 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
1263 return;
1264 } else if (V_BITS64_UNDEFINED == vbytes) {
1265 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
1266 return;
1267 }
1268 /* else fall into the slow case */
1269 }
1270 /* else fall into the slow case */
1271 }
bart5dd8e6a2008-03-22 08:04:29 +00001272 if (LIKELY(sizeof(void*) == 8
sewardj05a46732006-10-17 01:28:10 +00001273 && nBits == 32 && VG_IS_4_ALIGNED(a))) {
1274 SecMap* sm = get_secmap_for_reading(a);
1275 UWord sm_off = SM_OFF(a);
1276 UWord vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00001277 if (LIKELY( !is_distinguished_sm(sm) &&
sewardj05a46732006-10-17 01:28:10 +00001278 (VA_BITS8_DEFINED == vabits8 ||
1279 VA_BITS8_UNDEFINED == vabits8) )) {
1280 /* Handle common case quickly: a is suitably aligned, */
1281 /* is mapped, and is addressible. */
1282 // Convert full V-bits in register to compact 2-bit form.
bart5dd8e6a2008-03-22 08:04:29 +00001283 if (LIKELY(V_BITS32_DEFINED == (vbytes & 0xFFFFFFFF))) {
sewardj05a46732006-10-17 01:28:10 +00001284 sm->vabits8[sm_off] = VA_BITS8_DEFINED;
1285 return;
1286 } else if (V_BITS32_UNDEFINED == (vbytes & 0xFFFFFFFF)) {
1287 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
1288 return;
1289 }
1290 /* else fall into the slow case */
1291 }
1292 /* else fall into the slow case */
1293 }
1294 /* ------------ END semi-fast cases ------------ */
1295
njn45e81252006-03-28 12:35:08 +00001296 tl_assert(nBits == 64 || nBits == 32 || nBits == 16 || nBits == 8);
sewardj45d94cc2005-04-20 14:44:11 +00001297
1298 /* Dump vbytes in memory, iterating from least to most significant
njn718d3b12006-12-16 00:54:12 +00001299 byte. At the same time establish addressibility of the location. */
sewardj45d94cc2005-04-20 14:44:11 +00001300 for (i = 0; i < szB; i++) {
sewardjc1a2cda2005-04-21 17:34:00 +00001301 PROF_EVENT(36, "mc_STOREVn_slow(loop)");
njn45e81252006-03-28 12:35:08 +00001302 ai = a + byte_offset_w(szB, bigendian, i);
njn1d0825f2006-03-27 11:37:07 +00001303 vbits8 = vbytes & 0xff;
1304 ok = set_vbits8(ai, vbits8);
1305 if (!ok) n_addrs_bad++;
sewardj45d94cc2005-04-20 14:44:11 +00001306 vbytes >>= 8;
1307 }
1308
1309 /* If an address error has happened, report it. */
1310 if (n_addrs_bad > 0)
sewardj7ce71662008-05-02 10:33:15 +00001311 MC_(record_address_error)( VG_(get_running_tid)(), a, szB, True );
sewardj45d94cc2005-04-20 14:44:11 +00001312}
1313
1314
njn25e49d8e72002-09-23 09:36:25 +00001315/*------------------------------------------------------------*/
1316/*--- Setting permissions over address ranges. ---*/
1317/*------------------------------------------------------------*/
1318
njn1d0825f2006-03-27 11:37:07 +00001319static void set_address_range_perms ( Addr a, SizeT lenT, UWord vabits16,
1320 UWord dsm_num )
sewardj23eb2fd2005-04-22 16:29:19 +00001321{
njn1d0825f2006-03-27 11:37:07 +00001322 UWord sm_off, sm_off16;
1323 UWord vabits2 = vabits16 & 0x3;
1324 SizeT lenA, lenB, len_to_next_secmap;
1325 Addr aNext;
sewardjae986ca2005-10-12 12:53:20 +00001326 SecMap* sm;
njn1d0825f2006-03-27 11:37:07 +00001327 SecMap** sm_ptr;
sewardjae986ca2005-10-12 12:53:20 +00001328 SecMap* example_dsm;
1329
sewardj23eb2fd2005-04-22 16:29:19 +00001330 PROF_EVENT(150, "set_address_range_perms");
1331
njn1d0825f2006-03-27 11:37:07 +00001332 /* Check the V+A bits make sense. */
njndbf7ca72006-03-31 11:57:59 +00001333 tl_assert(VA_BITS16_NOACCESS == vabits16 ||
1334 VA_BITS16_UNDEFINED == vabits16 ||
1335 VA_BITS16_DEFINED == vabits16);
sewardj23eb2fd2005-04-22 16:29:19 +00001336
njn1d0825f2006-03-27 11:37:07 +00001337 // This code should never write PDBs; ensure this. (See comment above
1338 // set_vabits2().)
njndbf7ca72006-03-31 11:57:59 +00001339 tl_assert(VA_BITS2_PARTDEFINED != vabits2);
njn1d0825f2006-03-27 11:37:07 +00001340
1341 if (lenT == 0)
sewardj23eb2fd2005-04-22 16:29:19 +00001342 return;
1343
njn1d0825f2006-03-27 11:37:07 +00001344 if (lenT > 100 * 1000 * 1000) {
1345 if (VG_(clo_verbosity) > 0 && !VG_(clo_xml)) {
1346 Char* s = "unknown???";
njndbf7ca72006-03-31 11:57:59 +00001347 if (vabits16 == VA_BITS16_NOACCESS ) s = "noaccess";
1348 if (vabits16 == VA_BITS16_UNDEFINED) s = "undefined";
1349 if (vabits16 == VA_BITS16_DEFINED ) s = "defined";
njn1d0825f2006-03-27 11:37:07 +00001350 VG_(message)(Vg_UserMsg, "Warning: set address range perms: "
1351 "large range %lu (%s)", lenT, s);
sewardj23eb2fd2005-04-22 16:29:19 +00001352 }
1353 }
1354
njn1d0825f2006-03-27 11:37:07 +00001355#ifndef PERF_FAST_SARP
sewardj23eb2fd2005-04-22 16:29:19 +00001356 /*------------------ debug-only case ------------------ */
njn1d0825f2006-03-27 11:37:07 +00001357 {
1358 // Endianness doesn't matter here because all bytes are being set to
1359 // the same value.
1360 // Nb: We don't have to worry about updating the sec-V-bits table
1361 // after these set_vabits2() calls because this code never writes
njndbf7ca72006-03-31 11:57:59 +00001362 // VA_BITS2_PARTDEFINED values.
njn1d0825f2006-03-27 11:37:07 +00001363 SizeT i;
1364 for (i = 0; i < lenT; i++) {
1365 set_vabits2(a + i, vabits2);
1366 }
1367 return;
njn25e49d8e72002-09-23 09:36:25 +00001368 }
njn1d0825f2006-03-27 11:37:07 +00001369#endif
sewardj23eb2fd2005-04-22 16:29:19 +00001370
1371 /*------------------ standard handling ------------------ */
sewardj23eb2fd2005-04-22 16:29:19 +00001372
njn1d0825f2006-03-27 11:37:07 +00001373 /* Get the distinguished secondary that we might want
sewardj23eb2fd2005-04-22 16:29:19 +00001374 to use (part of the space-compression scheme). */
njn1d0825f2006-03-27 11:37:07 +00001375 example_dsm = &sm_distinguished[dsm_num];
1376
1377 // We have to handle ranges covering various combinations of partial and
1378 // whole sec-maps. Here is how parts 1, 2 and 3 are used in each case.
1379 // Cases marked with a '*' are common.
1380 //
1381 // TYPE PARTS USED
1382 // ---- ----------
1383 // * one partial sec-map (p) 1
1384 // - one whole sec-map (P) 2
1385 //
1386 // * two partial sec-maps (pp) 1,3
1387 // - one partial, one whole sec-map (pP) 1,2
1388 // - one whole, one partial sec-map (Pp) 2,3
1389 // - two whole sec-maps (PP) 2,2
1390 //
1391 // * one partial, one whole, one partial (pPp) 1,2,3
1392 // - one partial, two whole (pPP) 1,2,2
1393 // - two whole, one partial (PPp) 2,2,3
1394 // - three whole (PPP) 2,2,2
1395 //
1396 // * one partial, N-2 whole, one partial (pP...Pp) 1,2...2,3
1397 // - one partial, N-1 whole (pP...PP) 1,2...2,2
1398 // - N-1 whole, one partial (PP...Pp) 2,2...2,3
1399 // - N whole (PP...PP) 2,2...2,3
1400
1401 // Break up total length (lenT) into two parts: length in the first
1402 // sec-map (lenA), and the rest (lenB); lenT == lenA + lenB.
1403 aNext = start_of_this_sm(a) + SM_SIZE;
1404 len_to_next_secmap = aNext - a;
1405 if ( lenT <= len_to_next_secmap ) {
1406 // Range entirely within one sec-map. Covers almost all cases.
1407 PROF_EVENT(151, "set_address_range_perms-single-secmap");
1408 lenA = lenT;
1409 lenB = 0;
1410 } else if (is_start_of_sm(a)) {
1411 // Range spans at least one whole sec-map, and starts at the beginning
1412 // of a sec-map; skip to Part 2.
1413 PROF_EVENT(152, "set_address_range_perms-startof-secmap");
1414 lenA = 0;
1415 lenB = lenT;
1416 goto part2;
sewardj23eb2fd2005-04-22 16:29:19 +00001417 } else {
njn1d0825f2006-03-27 11:37:07 +00001418 // Range spans two or more sec-maps, first one is partial.
1419 PROF_EVENT(153, "set_address_range_perms-multiple-secmaps");
1420 lenA = len_to_next_secmap;
1421 lenB = lenT - lenA;
1422 }
1423
1424 //------------------------------------------------------------------------
1425 // Part 1: Deal with the first sec_map. Most of the time the range will be
1426 // entirely within a sec_map and this part alone will suffice. Also,
1427 // doing it this way lets us avoid repeatedly testing for the crossing of
1428 // a sec-map boundary within these loops.
1429 //------------------------------------------------------------------------
1430
1431 // If it's distinguished, make it undistinguished if necessary.
1432 sm_ptr = get_secmap_ptr(a);
1433 if (is_distinguished_sm(*sm_ptr)) {
1434 if (*sm_ptr == example_dsm) {
1435 // Sec-map already has the V+A bits that we want, so skip.
1436 PROF_EVENT(154, "set_address_range_perms-dist-sm1-quick");
1437 a = aNext;
1438 lenA = 0;
sewardj23eb2fd2005-04-22 16:29:19 +00001439 } else {
njn1d0825f2006-03-27 11:37:07 +00001440 PROF_EVENT(155, "set_address_range_perms-dist-sm1");
1441 *sm_ptr = copy_for_writing(*sm_ptr);
sewardj23eb2fd2005-04-22 16:29:19 +00001442 }
1443 }
njn1d0825f2006-03-27 11:37:07 +00001444 sm = *sm_ptr;
sewardj23eb2fd2005-04-22 16:29:19 +00001445
njn1d0825f2006-03-27 11:37:07 +00001446 // 1 byte steps
sewardj23eb2fd2005-04-22 16:29:19 +00001447 while (True) {
sewardj23eb2fd2005-04-22 16:29:19 +00001448 if (VG_IS_8_ALIGNED(a)) break;
njn1d0825f2006-03-27 11:37:07 +00001449 if (lenA < 1) break;
1450 PROF_EVENT(156, "set_address_range_perms-loop1a");
1451 sm_off = SM_OFF(a);
1452 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1453 a += 1;
1454 lenA -= 1;
1455 }
1456 // 8-aligned, 8 byte steps
sewardj23eb2fd2005-04-22 16:29:19 +00001457 while (True) {
njn1d0825f2006-03-27 11:37:07 +00001458 if (lenA < 8) break;
1459 PROF_EVENT(157, "set_address_range_perms-loop8a");
1460 sm_off16 = SM_OFF_16(a);
1461 ((UShort*)(sm->vabits8))[sm_off16] = vabits16;
1462 a += 8;
1463 lenA -= 8;
1464 }
1465 // 1 byte steps
1466 while (True) {
1467 if (lenA < 1) break;
1468 PROF_EVENT(158, "set_address_range_perms-loop1b");
1469 sm_off = SM_OFF(a);
1470 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1471 a += 1;
1472 lenA -= 1;
sewardj23eb2fd2005-04-22 16:29:19 +00001473 }
1474
njn1d0825f2006-03-27 11:37:07 +00001475 // We've finished the first sec-map. Is that it?
1476 if (lenB == 0)
sewardj23eb2fd2005-04-22 16:29:19 +00001477 return;
1478
njn1d0825f2006-03-27 11:37:07 +00001479 //------------------------------------------------------------------------
1480 // Part 2: Fast-set entire sec-maps at a time.
1481 //------------------------------------------------------------------------
1482 part2:
1483 // 64KB-aligned, 64KB steps.
1484 // Nb: we can reach here with lenB < SM_SIZE
sewardj23eb2fd2005-04-22 16:29:19 +00001485 while (True) {
njn1d0825f2006-03-27 11:37:07 +00001486 if (lenB < SM_SIZE) break;
1487 tl_assert(is_start_of_sm(a));
1488 PROF_EVENT(159, "set_address_range_perms-loop64K");
1489 sm_ptr = get_secmap_ptr(a);
1490 if (!is_distinguished_sm(*sm_ptr)) {
1491 PROF_EVENT(160, "set_address_range_perms-loop64K-free-dist-sm");
1492 // Free the non-distinguished sec-map that we're replacing. This
1493 // case happens moderately often, enough to be worthwhile.
1494 VG_(am_munmap_valgrind)((Addr)*sm_ptr, sizeof(SecMap));
1495 }
1496 update_SM_counts(*sm_ptr, example_dsm);
1497 // Make the sec-map entry point to the example DSM
1498 *sm_ptr = example_dsm;
1499 lenB -= SM_SIZE;
1500 a += SM_SIZE;
1501 }
sewardj23eb2fd2005-04-22 16:29:19 +00001502
njn1d0825f2006-03-27 11:37:07 +00001503 // We've finished the whole sec-maps. Is that it?
1504 if (lenB == 0)
1505 return;
1506
1507 //------------------------------------------------------------------------
1508 // Part 3: Finish off the final partial sec-map, if necessary.
1509 //------------------------------------------------------------------------
1510
1511 tl_assert(is_start_of_sm(a) && lenB < SM_SIZE);
1512
1513 // If it's distinguished, make it undistinguished if necessary.
1514 sm_ptr = get_secmap_ptr(a);
1515 if (is_distinguished_sm(*sm_ptr)) {
1516 if (*sm_ptr == example_dsm) {
1517 // Sec-map already has the V+A bits that we want, so stop.
1518 PROF_EVENT(161, "set_address_range_perms-dist-sm2-quick");
1519 return;
1520 } else {
1521 PROF_EVENT(162, "set_address_range_perms-dist-sm2");
1522 *sm_ptr = copy_for_writing(*sm_ptr);
1523 }
1524 }
1525 sm = *sm_ptr;
1526
1527 // 8-aligned, 8 byte steps
1528 while (True) {
1529 if (lenB < 8) break;
1530 PROF_EVENT(163, "set_address_range_perms-loop8b");
1531 sm_off16 = SM_OFF_16(a);
1532 ((UShort*)(sm->vabits8))[sm_off16] = vabits16;
1533 a += 8;
1534 lenB -= 8;
1535 }
1536 // 1 byte steps
1537 while (True) {
1538 if (lenB < 1) return;
1539 PROF_EVENT(164, "set_address_range_perms-loop1c");
1540 sm_off = SM_OFF(a);
1541 insert_vabits2_into_vabits8( a, vabits2, &(sm->vabits8[sm_off]) );
1542 a += 1;
1543 lenB -= 1;
1544 }
sewardj23eb2fd2005-04-22 16:29:19 +00001545}
sewardj45d94cc2005-04-20 14:44:11 +00001546
sewardjc859fbf2005-04-22 21:10:28 +00001547
1548/* --- Set permissions for arbitrary address ranges --- */
njn25e49d8e72002-09-23 09:36:25 +00001549
njndbf7ca72006-03-31 11:57:59 +00001550void MC_(make_mem_noaccess) ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001551{
njndbf7ca72006-03-31 11:57:59 +00001552 PROF_EVENT(40, "MC_(make_mem_noaccess)");
1553 DEBUG("MC_(make_mem_noaccess)(%p, %lu)\n", a, len);
njn1d0825f2006-03-27 11:37:07 +00001554 set_address_range_perms ( a, len, VA_BITS16_NOACCESS, SM_DIST_NOACCESS );
sewardj7cf4e6b2008-05-01 20:24:26 +00001555 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1556 ocache_sarp_Clear_Origins ( a, len );
njn25e49d8e72002-09-23 09:36:25 +00001557}
1558
sewardj7cf4e6b2008-05-01 20:24:26 +00001559static void make_mem_undefined ( Addr a, SizeT len )
1560{
1561 PROF_EVENT(41, "make_mem_undefined");
1562 DEBUG("make_mem_undefined(%p, %lu)\n", a, len);
1563 set_address_range_perms ( a, len, VA_BITS16_UNDEFINED, SM_DIST_UNDEFINED );
1564}
1565
1566void MC_(make_mem_undefined_w_otag) ( Addr a, SizeT len, UInt otag )
njn25e49d8e72002-09-23 09:36:25 +00001567{
njndbf7ca72006-03-31 11:57:59 +00001568 PROF_EVENT(41, "MC_(make_mem_undefined)");
1569 DEBUG("MC_(make_mem_undefined)(%p, %lu)\n", a, len);
1570 set_address_range_perms ( a, len, VA_BITS16_UNDEFINED, SM_DIST_UNDEFINED );
sewardj7cf4e6b2008-05-01 20:24:26 +00001571 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1572 ocache_sarp_Set_Origins ( a, len, otag );
njn25e49d8e72002-09-23 09:36:25 +00001573}
1574
sewardj7cf4e6b2008-05-01 20:24:26 +00001575static
1576void make_mem_undefined_w_tid_and_okind ( Addr a, SizeT len,
1577 ThreadId tid, UInt okind )
1578{
1579 UInt ecu;
1580 ExeContext* here;
1581 /* VG_(record_ExeContext) checks for validity of tid, and asserts
1582 if it is invalid. So no need to do it here. */
1583 tl_assert(okind <= 3);
1584 here = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ );
1585 tl_assert(here);
1586 ecu = VG_(get_ECU_from_ExeContext)(here);
1587 tl_assert(VG_(is_plausible_ECU)(ecu));
1588 MC_(make_mem_undefined_w_otag) ( a, len, ecu | okind );
1589}
1590
1591static
1592void make_mem_undefined_w_tid ( Addr a, SizeT len, ThreadId tid ) {
1593 make_mem_undefined_w_tid_and_okind ( a, len, tid, MC_OKIND_UNKNOWN );
1594}
1595
1596
njndbf7ca72006-03-31 11:57:59 +00001597void MC_(make_mem_defined) ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +00001598{
njndbf7ca72006-03-31 11:57:59 +00001599 PROF_EVENT(42, "MC_(make_mem_defined)");
1600 DEBUG("MC_(make_mem_defined)(%p, %lu)\n", a, len);
1601 set_address_range_perms ( a, len, VA_BITS16_DEFINED, SM_DIST_DEFINED );
sewardj7cf4e6b2008-05-01 20:24:26 +00001602 if (UNLIKELY( MC_(clo_mc_level) == 3 ))
1603 ocache_sarp_Clear_Origins ( a, len );
njn25e49d8e72002-09-23 09:36:25 +00001604}
1605
sewardjfb1e9ad2006-03-10 13:41:58 +00001606/* For each byte in [a,a+len), if the byte is addressable, make it be
1607 defined, but if it isn't addressible, leave it alone. In other
njndbf7ca72006-03-31 11:57:59 +00001608 words a version of MC_(make_mem_defined) that doesn't mess with
sewardjfb1e9ad2006-03-10 13:41:58 +00001609 addressibility. Low-performance implementation. */
njndbf7ca72006-03-31 11:57:59 +00001610static void make_mem_defined_if_addressable ( Addr a, SizeT len )
sewardjfb1e9ad2006-03-10 13:41:58 +00001611{
1612 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00001613 UChar vabits2;
njndbf7ca72006-03-31 11:57:59 +00001614 DEBUG("make_mem_defined_if_addressable(%p, %llu)\n", a, (ULong)len);
sewardjfb1e9ad2006-03-10 13:41:58 +00001615 for (i = 0; i < len; i++) {
njn1d0825f2006-03-27 11:37:07 +00001616 vabits2 = get_vabits2( a+i );
bart5dd8e6a2008-03-22 08:04:29 +00001617 if (LIKELY(VA_BITS2_NOACCESS != vabits2)) {
njndbf7ca72006-03-31 11:57:59 +00001618 set_vabits2(a+i, VA_BITS2_DEFINED);
sewardj7cf4e6b2008-05-01 20:24:26 +00001619 if (UNLIKELY(MC_(clo_mc_level) >= 3)) {
1620 MC_(helperc_b_store1)( a+i, 0 ); /* clear the origin tag */
1621 }
njn1d0825f2006-03-27 11:37:07 +00001622 }
sewardjfb1e9ad2006-03-10 13:41:58 +00001623 }
1624}
1625
njn9b007f62003-04-07 14:40:25 +00001626
sewardj45f4e7c2005-09-27 19:20:21 +00001627/* --- Block-copy permissions (needed for implementing realloc() and
1628 sys_mremap). --- */
sewardjc859fbf2005-04-22 21:10:28 +00001629
njn1d0825f2006-03-27 11:37:07 +00001630void MC_(copy_address_range_state) ( Addr src, Addr dst, SizeT len )
sewardjc859fbf2005-04-22 21:10:28 +00001631{
sewardj45f4e7c2005-09-27 19:20:21 +00001632 SizeT i, j;
sewardjf2184912006-05-03 22:13:57 +00001633 UChar vabits2, vabits8;
1634 Bool aligned, nooverlap;
sewardjc859fbf2005-04-22 21:10:28 +00001635
njn1d0825f2006-03-27 11:37:07 +00001636 DEBUG("MC_(copy_address_range_state)\n");
1637 PROF_EVENT(50, "MC_(copy_address_range_state)");
sewardj45f4e7c2005-09-27 19:20:21 +00001638
sewardjf2184912006-05-03 22:13:57 +00001639 if (len == 0 || src == dst)
sewardj45f4e7c2005-09-27 19:20:21 +00001640 return;
1641
sewardjf2184912006-05-03 22:13:57 +00001642 aligned = VG_IS_4_ALIGNED(src) && VG_IS_4_ALIGNED(dst);
1643 nooverlap = src+len <= dst || dst+len <= src;
sewardj45f4e7c2005-09-27 19:20:21 +00001644
sewardjf2184912006-05-03 22:13:57 +00001645 if (nooverlap && aligned) {
1646
1647 /* Vectorised fast case, when no overlap and suitably aligned */
1648 /* vector loop */
1649 i = 0;
1650 while (len >= 4) {
1651 vabits8 = get_vabits8_for_aligned_word32( src+i );
1652 set_vabits8_for_aligned_word32( dst+i, vabits8 );
bart5dd8e6a2008-03-22 08:04:29 +00001653 if (LIKELY(VA_BITS8_DEFINED == vabits8
sewardjf2184912006-05-03 22:13:57 +00001654 || VA_BITS8_UNDEFINED == vabits8
1655 || VA_BITS8_NOACCESS == vabits8)) {
1656 /* do nothing */
1657 } else {
1658 /* have to copy secondary map info */
1659 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+0 ))
1660 set_sec_vbits8( dst+i+0, get_sec_vbits8( src+i+0 ) );
1661 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+1 ))
1662 set_sec_vbits8( dst+i+1, get_sec_vbits8( src+i+1 ) );
1663 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+2 ))
1664 set_sec_vbits8( dst+i+2, get_sec_vbits8( src+i+2 ) );
1665 if (VA_BITS2_PARTDEFINED == get_vabits2( src+i+3 ))
1666 set_sec_vbits8( dst+i+3, get_sec_vbits8( src+i+3 ) );
1667 }
1668 i += 4;
1669 len -= 4;
1670 }
1671 /* fixup loop */
1672 while (len >= 1) {
njn1d0825f2006-03-27 11:37:07 +00001673 vabits2 = get_vabits2( src+i );
1674 set_vabits2( dst+i, vabits2 );
njndbf7ca72006-03-31 11:57:59 +00001675 if (VA_BITS2_PARTDEFINED == vabits2) {
njn1d0825f2006-03-27 11:37:07 +00001676 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1677 }
sewardjf2184912006-05-03 22:13:57 +00001678 i++;
1679 len--;
1680 }
1681
1682 } else {
1683
1684 /* We have to do things the slow way */
1685 if (src < dst) {
1686 for (i = 0, j = len-1; i < len; i++, j--) {
1687 PROF_EVENT(51, "MC_(copy_address_range_state)(loop)");
1688 vabits2 = get_vabits2( src+j );
1689 set_vabits2( dst+j, vabits2 );
1690 if (VA_BITS2_PARTDEFINED == vabits2) {
1691 set_sec_vbits8( dst+j, get_sec_vbits8( src+j ) );
1692 }
1693 }
1694 }
1695
1696 if (src > dst) {
1697 for (i = 0; i < len; i++) {
1698 PROF_EVENT(52, "MC_(copy_address_range_state)(loop)");
1699 vabits2 = get_vabits2( src+i );
1700 set_vabits2( dst+i, vabits2 );
1701 if (VA_BITS2_PARTDEFINED == vabits2) {
1702 set_sec_vbits8( dst+i, get_sec_vbits8( src+i ) );
1703 }
1704 }
sewardj45f4e7c2005-09-27 19:20:21 +00001705 }
sewardjc859fbf2005-04-22 21:10:28 +00001706 }
sewardjf2184912006-05-03 22:13:57 +00001707
sewardjc859fbf2005-04-22 21:10:28 +00001708}
1709
1710
sewardj7cf4e6b2008-05-01 20:24:26 +00001711/*------------------------------------------------------------*/
1712/*--- Origin tracking stuff - cache basics ---*/
1713/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00001714
sewardj7cf4e6b2008-05-01 20:24:26 +00001715/* Some background comments on the origin tracking implementation
1716 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1717
1718 Note that this implementation draws inspiration from the "origin
1719 tracking by value piggybacking" scheme described in "Tracking Bad
1720 Apples: Reporting the Origin of Null and Undefined Value Errors"
1721 (Michael Bond, Nicholas Nethercote, Stephen Kent, Samuel Guyer,
1722 Kathryn McKinley, OOPSLA07, Montreal, Oct 2007) but in fact it is
1723 implemented completely differently.
1724
1725 This implementation tracks the defining point of all values using
1726 so called "origin tags", which are 32-bit integers, rather than
1727 using the values themselves to encode the origins. The latter,
1728 so-called value piggybacking", is what the OOPSLA07 paper
1729 describes.
1730
1731 Origin tags, as tracked by the machinery below, are 32-bit unsigned
1732 ints (UInts), regardless of the machine's word size.
1733
1734 > Question: why is otag a UInt? Wouldn't a UWord be better? Isn't
1735 > it really just the address of the relevant ExeContext?
1736
1737 Well, it's not the address, but a value which has a 1-1 mapping
1738 with ExeContexts, and is guaranteed not to be zero, since zero
1739 denotes (to memcheck) "unknown origin or defined value". So these
1740 UInts are just numbers starting at 1; each ExeContext is given a
1741 number when it is created.
1742
1743 Making these otags 32-bit regardless of the machine's word size
1744 makes the 64-bit implementation easier (next para). And it doesn't
1745 really limit us in any way, since for the tags to overflow would
1746 require that the program somehow caused 2^32-1 different
1747 ExeContexts to be created, in which case it is probably in deep
1748 trouble. Not to mention V will have soaked up many tens of
1749 gigabytes of memory merely to store them all.
1750
1751 So having 64-bit origins doesn't really buy you anything, and has
1752 the following downsides:
1753
1754 Suppose that instead, an otag is a UWord. This would mean that, on
1755 a 64-bit target,
1756
1757 1. It becomes hard to shadow any element of guest state which is
1758 smaller than 8 bytes. To do so means you'd need to find some
1759 8-byte-sized hole in the guest state which you don't want to
1760 shadow, and use that instead to hold the otag. On ppc64, the
1761 condition code register(s) are split into 20 UChar sized pieces,
1762 all of which need to be tracked (guest_XER_SO .. guest_CR7_0)
1763 and so that would entail finding 160 bytes somewhere else in the
1764 guest state.
1765
1766 Even on x86, I want to track origins for %AH .. %DH (bits 15:8
1767 of %EAX .. %EDX) that are separate from %AL .. %DL (bits 7:0 of
1768 same) and so I had to look for 4 untracked otag-sized areas in
1769 the guest state to make that possible.
1770
1771 The same problem exists of course when origin tags are only 32
1772 bits, but it's less extreme.
1773
1774 2. (More compelling) it doubles the size of the origin shadow
1775 memory. Given that the shadow memory is organised as a fixed
1776 size cache, and that accuracy of tracking is limited by origins
1777 falling out the cache due to space conflicts, this isn't good.
1778
1779 > Another question: is the origin tracking perfect, or are there
1780 > cases where it fails to determine an origin?
1781
1782 It is imperfect for at least for the following reasons, and
1783 probably more:
1784
1785 * Insufficient capacity in the origin cache. When a line is
1786 evicted from the cache it is gone forever, and so subsequent
1787 queries for the line produce zero, indicating no origin
1788 information. Interestingly, a line containing all zeroes can be
1789 evicted "free" from the cache, since it contains no useful
1790 information, so there is scope perhaps for some cleverer cache
1791 management schemes.
1792
1793 * The origin cache only stores one otag per 32-bits of address
1794 space, plus 4 bits indicating which of the 4 bytes has that tag
1795 and which are considered defined. The result is that if two
1796 undefined bytes in the same word are stored in memory, the first
1797 stored byte's origin will be lost and replaced by the origin for
1798 the second byte.
1799
1800 * Nonzero origin tags for defined values. Consider a binary
1801 operator application op(x,y). Suppose y is undefined (and so has
1802 a valid nonzero origin tag), and x is defined, but erroneously
1803 has a nonzero origin tag (defined values should have tag zero).
1804 If the erroneous tag has a numeric value greater than y's tag,
1805 then the rule for propagating origin tags though binary
1806 operations, which is simply to take the unsigned max of the two
1807 tags, will erroneously propagate x's tag rather than y's.
1808
1809 * Some obscure uses of x86/amd64 byte registers can cause lossage
1810 or confusion of origins. %AH .. %DH are treated as different
1811 from, and unrelated to, their parent registers, %EAX .. %EDX.
1812 So some wierd sequences like
1813
1814 movb undefined-value, %AH
1815 movb defined-value, %AL
1816 .. use %AX or %EAX ..
1817
1818 will cause the origin attributed to %AH to be ignored, since %AL,
1819 %AX, %EAX are treated as the same register, and %AH as a
1820 completely separate one.
1821
1822 But having said all that, it actually seems to work fairly well in
1823 practice.
1824*/
1825
1826static UWord stats_ocacheL1_find = 0;
1827static UWord stats_ocacheL1_found_at_1 = 0;
1828static UWord stats_ocacheL1_found_at_N = 0;
1829static UWord stats_ocacheL1_misses = 0;
1830static UWord stats_ocacheL1_lossage = 0;
1831static UWord stats_ocacheL1_movefwds = 0;
1832
1833static UWord stats__ocacheL2_refs = 0;
1834static UWord stats__ocacheL2_misses = 0;
1835static UWord stats__ocacheL2_n_nodes_max = 0;
1836
1837/* Cache of 32-bit values, one every 32 bits of address space */
1838
1839#define OC_BITS_PER_LINE 5
1840#define OC_W32S_PER_LINE (1 << (OC_BITS_PER_LINE - 2))
1841
1842static INLINE UWord oc_line_offset ( Addr a ) {
1843 return (a >> 2) & (OC_W32S_PER_LINE - 1);
1844}
1845static INLINE Bool is_valid_oc_tag ( Addr tag ) {
1846 return 0 == (tag & ((1 << OC_BITS_PER_LINE) - 1));
1847}
1848
1849#define OC_LINES_PER_SET 2
1850
1851#define OC_N_SET_BITS 20
1852#define OC_N_SETS (1 << OC_N_SET_BITS)
1853
1854/* These settings give:
1855 64 bit host: ocache: 100,663,296 sizeB 67,108,864 useful
1856 32 bit host: ocache: 92,274,688 sizeB 67,108,864 useful
1857*/
1858
1859#define OC_MOVE_FORWARDS_EVERY_BITS 7
1860
1861
1862typedef
1863 struct {
1864 Addr tag;
1865 UInt w32[OC_W32S_PER_LINE];
1866 UChar descr[OC_W32S_PER_LINE];
1867 }
1868 OCacheLine;
1869
1870/* Classify and also sanity-check 'line'. Return 'e' (empty) if not
1871 in use, 'n' (nonzero) if it contains at least one valid origin tag,
1872 and 'z' if all the represented tags are zero. */
1873static UChar classify_OCacheLine ( OCacheLine* line )
1874{
1875 UWord i;
1876 if (line->tag == 1/*invalid*/)
1877 return 'e'; /* EMPTY */
1878 tl_assert(is_valid_oc_tag(line->tag));
1879 for (i = 0; i < OC_W32S_PER_LINE; i++) {
1880 tl_assert(0 == ((~0xF) & line->descr[i]));
1881 if (line->w32[i] > 0 && line->descr[i] > 0)
1882 return 'n'; /* NONZERO - contains useful info */
1883 }
1884 return 'z'; /* ZERO - no useful info */
1885}
1886
1887typedef
1888 struct {
1889 OCacheLine line[OC_LINES_PER_SET];
1890 }
1891 OCacheSet;
1892
1893typedef
1894 struct {
1895 OCacheSet set[OC_N_SETS];
1896 }
1897 OCache;
1898
sewardj9d624d12008-05-02 13:35:29 +00001899static OCache* ocache = NULL;
1900static UWord ocache_event_ctr = 0;
sewardj7cf4e6b2008-05-01 20:24:26 +00001901
1902static void init_ocacheL2 ( void ); /* fwds */
1903static void init_OCache ( void )
1904{
1905 UWord line, set;
sewardj9d624d12008-05-02 13:35:29 +00001906 tl_assert(MC_(clo_mc_level) >= 3);
1907 tl_assert(ocache == NULL);
1908 ocache = VG_(am_shadow_alloc)(sizeof(OCache));
1909 if (ocache == NULL) {
1910 VG_(out_of_memory_NORETURN)( "memcheck:allocate the OCache",
1911 sizeof(OCache) );
1912 }
1913 tl_assert(ocache != NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00001914 for (set = 0; set < OC_N_SETS; set++) {
1915 for (line = 0; line < OC_LINES_PER_SET; line++) {
sewardj9d624d12008-05-02 13:35:29 +00001916 ocache->set[set].line[line].tag = 1/*invalid*/;
sewardj7cf4e6b2008-05-01 20:24:26 +00001917 }
1918 }
1919 init_ocacheL2();
1920}
1921
1922static void moveLineForwards ( OCacheSet* set, UWord lineno )
1923{
1924 OCacheLine tmp;
1925 stats_ocacheL1_movefwds++;
1926 tl_assert(lineno > 0 && lineno < OC_LINES_PER_SET);
1927 tmp = set->line[lineno-1];
1928 set->line[lineno-1] = set->line[lineno];
1929 set->line[lineno] = tmp;
1930}
1931
1932static void zeroise_OCacheLine ( OCacheLine* line, Addr tag ) {
1933 UWord i;
1934 for (i = 0; i < OC_W32S_PER_LINE; i++) {
1935 line->w32[i] = 0; /* NO ORIGIN */
1936 line->descr[i] = 0; /* REALLY REALLY NO ORIGIN! */
1937 }
1938 line->tag = tag;
1939}
1940
1941//////////////////////////////////////////////////////////////
1942//// OCache backing store
1943
1944static OSet* ocacheL2 = NULL;
1945
1946static void* ocacheL2_malloc ( SizeT szB ) {
1947 return VG_(malloc)(szB);
1948}
1949static void ocacheL2_free ( void* v ) {
1950 VG_(free)( v );
1951}
1952
1953/* Stats: # nodes currently in tree */
1954static UWord stats__ocacheL2_n_nodes = 0;
1955
1956static void init_ocacheL2 ( void )
1957{
1958 tl_assert(!ocacheL2);
1959 tl_assert(sizeof(Word) == sizeof(Addr)); /* since OCacheLine.tag :: Addr */
1960 tl_assert(0 == offsetof(OCacheLine,tag));
1961 ocacheL2
1962 = VG_(OSetGen_Create)( offsetof(OCacheLine,tag),
1963 NULL, /* fast cmp */
1964 ocacheL2_malloc, ocacheL2_free );
1965 tl_assert(ocacheL2);
1966 stats__ocacheL2_n_nodes = 0;
1967}
1968
1969/* Find line with the given tag in the tree, or NULL if not found. */
1970static OCacheLine* ocacheL2_find_tag ( Addr tag )
1971{
1972 OCacheLine* line;
1973 tl_assert(is_valid_oc_tag(tag));
1974 stats__ocacheL2_refs++;
1975 line = VG_(OSetGen_Lookup)( ocacheL2, &tag );
1976 return line;
1977}
1978
1979/* Delete the line with the given tag from the tree, if it is present, and
1980 free up the associated memory. */
1981static void ocacheL2_del_tag ( Addr tag )
1982{
1983 OCacheLine* line;
1984 tl_assert(is_valid_oc_tag(tag));
1985 stats__ocacheL2_refs++;
1986 line = VG_(OSetGen_Remove)( ocacheL2, &tag );
1987 if (line) {
1988 VG_(OSetGen_FreeNode)(ocacheL2, line);
1989 tl_assert(stats__ocacheL2_n_nodes > 0);
1990 stats__ocacheL2_n_nodes--;
1991 }
1992}
1993
1994/* Add a copy of the given line to the tree. It must not already be
1995 present. */
1996static void ocacheL2_add_line ( OCacheLine* line )
1997{
1998 OCacheLine* copy;
1999 tl_assert(is_valid_oc_tag(line->tag));
2000 copy = VG_(OSetGen_AllocNode)( ocacheL2, sizeof(OCacheLine) );
2001 tl_assert(copy);
2002 *copy = *line;
2003 stats__ocacheL2_refs++;
2004 VG_(OSetGen_Insert)( ocacheL2, copy );
2005 stats__ocacheL2_n_nodes++;
2006 if (stats__ocacheL2_n_nodes > stats__ocacheL2_n_nodes_max)
2007 stats__ocacheL2_n_nodes_max = stats__ocacheL2_n_nodes;
2008}
2009
2010////
2011//////////////////////////////////////////////////////////////
2012
2013__attribute__((noinline))
2014static OCacheLine* find_OCacheLine_SLOW ( Addr a )
2015{
2016 OCacheLine *victim, *inL2;
2017 UChar c;
2018 UWord line;
2019 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2020 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2021 UWord tag = a & tagmask;
2022 tl_assert(setno >= 0 && setno < OC_N_SETS);
2023
2024 /* we already tried line == 0; skip therefore. */
2025 for (line = 1; line < OC_LINES_PER_SET; line++) {
sewardj9d624d12008-05-02 13:35:29 +00002026 if (ocache->set[setno].line[line].tag == tag) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002027 if (line == 1) {
2028 stats_ocacheL1_found_at_1++;
2029 } else {
2030 stats_ocacheL1_found_at_N++;
2031 }
2032 if (UNLIKELY(0 == (ocache_event_ctr++
2033 & ((1<<OC_MOVE_FORWARDS_EVERY_BITS)-1)))) {
sewardj9d624d12008-05-02 13:35:29 +00002034 moveLineForwards( &ocache->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002035 line--;
2036 }
sewardj9d624d12008-05-02 13:35:29 +00002037 return &ocache->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002038 }
2039 }
2040
2041 /* A miss. Use the last slot. Implicitly this means we're
2042 ejecting the line in the last slot. */
2043 stats_ocacheL1_misses++;
2044 tl_assert(line == OC_LINES_PER_SET);
2045 line--;
2046 tl_assert(line > 0);
2047
2048 /* First, move the to-be-ejected line to the L2 cache. */
sewardj9d624d12008-05-02 13:35:29 +00002049 victim = &ocache->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002050 c = classify_OCacheLine(victim);
2051 switch (c) {
2052 case 'e':
2053 /* the line is empty (has invalid tag); ignore it. */
2054 break;
2055 case 'z':
2056 /* line contains zeroes. We must ensure the backing store is
2057 updated accordingly, either by copying the line there
2058 verbatim, or by ensuring it isn't present there. We
2059 chosse the latter on the basis that it reduces the size of
2060 the backing store. */
2061 ocacheL2_del_tag( victim->tag );
2062 break;
2063 case 'n':
2064 /* line contains at least one real, useful origin. Copy it
2065 to the backing store. */
2066 stats_ocacheL1_lossage++;
2067 inL2 = ocacheL2_find_tag( victim->tag );
2068 if (inL2) {
2069 *inL2 = *victim;
2070 } else {
2071 ocacheL2_add_line( victim );
2072 }
2073 break;
2074 default:
2075 tl_assert(0);
2076 }
2077
2078 /* Now we must reload the L1 cache from the backing tree, if
2079 possible. */
2080 tl_assert(tag != victim->tag); /* stay sane */
2081 inL2 = ocacheL2_find_tag( tag );
2082 if (inL2) {
2083 /* We're in luck. It's in the L2. */
sewardj9d624d12008-05-02 13:35:29 +00002084 ocache->set[setno].line[line] = *inL2;
sewardj7cf4e6b2008-05-01 20:24:26 +00002085 } else {
2086 /* Missed at both levels of the cache hierarchy. We have to
2087 declare it as full of zeroes (unknown origins). */
2088 stats__ocacheL2_misses++;
sewardj9d624d12008-05-02 13:35:29 +00002089 zeroise_OCacheLine( &ocache->set[setno].line[line], tag );
sewardj7cf4e6b2008-05-01 20:24:26 +00002090 }
2091
2092 /* Move it one forwards */
sewardj9d624d12008-05-02 13:35:29 +00002093 moveLineForwards( &ocache->set[setno], line );
sewardj7cf4e6b2008-05-01 20:24:26 +00002094 line--;
2095
sewardj9d624d12008-05-02 13:35:29 +00002096 return &ocache->set[setno].line[line];
sewardj7cf4e6b2008-05-01 20:24:26 +00002097}
2098
2099static INLINE OCacheLine* find_OCacheLine ( Addr a )
2100{
2101 UWord setno = (a >> OC_BITS_PER_LINE) & (OC_N_SETS - 1);
2102 UWord tagmask = ~((1 << OC_BITS_PER_LINE) - 1);
2103 UWord tag = a & tagmask;
2104
2105 stats_ocacheL1_find++;
2106
2107 if (OC_ENABLE_ASSERTIONS) {
2108 tl_assert(setno >= 0 && setno < OC_N_SETS);
2109 tl_assert(0 == (tag & (4 * OC_W32S_PER_LINE - 1)));
2110 }
2111
sewardj9d624d12008-05-02 13:35:29 +00002112 if (LIKELY(ocache->set[setno].line[0].tag == tag)) {
2113 return &ocache->set[setno].line[0];
sewardj7cf4e6b2008-05-01 20:24:26 +00002114 }
2115
2116 return find_OCacheLine_SLOW( a );
2117}
2118
2119static INLINE void set_aligned_word64_Origin_to_undef ( Addr a, UInt otag )
2120{
2121 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2122 //// Set the origins for a+0 .. a+7
2123 { OCacheLine* line;
2124 UWord lineoff = oc_line_offset(a);
2125 if (OC_ENABLE_ASSERTIONS) {
2126 tl_assert(lineoff >= 0
2127 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2128 }
2129 line = find_OCacheLine( a );
2130 line->descr[lineoff+0] = 0xF;
2131 line->descr[lineoff+1] = 0xF;
2132 line->w32[lineoff+0] = otag;
2133 line->w32[lineoff+1] = otag;
2134 }
2135 //// END inlined, specialised version of MC_(helperc_b_store8)
2136}
2137
2138
2139/*------------------------------------------------------------*/
2140/*--- Aligned fast case permission setters, ---*/
2141/*--- for dealing with stacks ---*/
2142/*------------------------------------------------------------*/
2143
2144/*--------------------- 32-bit ---------------------*/
2145
2146/* Nb: by "aligned" here we mean 4-byte aligned */
2147
2148static INLINE void make_aligned_word32_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002149{
njn1d0825f2006-03-27 11:37:07 +00002150 UWord sm_off;
sewardjae986ca2005-10-12 12:53:20 +00002151 SecMap* sm;
2152
njndbf7ca72006-03-31 11:57:59 +00002153 PROF_EVENT(300, "make_aligned_word32_undefined");
sewardj5d28efc2005-04-21 22:16:29 +00002154
njn1d0825f2006-03-27 11:37:07 +00002155#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002156 make_mem_undefined(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002157#else
bart5dd8e6a2008-03-22 08:04:29 +00002158 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
njndbf7ca72006-03-31 11:57:59 +00002159 PROF_EVENT(301, "make_aligned_word32_undefined-slow1");
sewardj7cf4e6b2008-05-01 20:24:26 +00002160 make_mem_undefined(a, 4);
sewardj5d28efc2005-04-21 22:16:29 +00002161 return;
2162 }
2163
njna7c7ebd2006-03-28 12:51:02 +00002164 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002165 sm_off = SM_OFF(a);
njndbf7ca72006-03-31 11:57:59 +00002166 sm->vabits8[sm_off] = VA_BITS8_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00002167#endif
njn9b007f62003-04-07 14:40:25 +00002168}
2169
sewardj7cf4e6b2008-05-01 20:24:26 +00002170static INLINE
2171void make_aligned_word32_undefined_w_otag ( Addr a, UInt otag )
2172{
2173 make_aligned_word32_undefined(a);
2174 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2175 //// Set the origins for a+0 .. a+3
2176 { OCacheLine* line;
2177 UWord lineoff = oc_line_offset(a);
2178 if (OC_ENABLE_ASSERTIONS) {
2179 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2180 }
2181 line = find_OCacheLine( a );
2182 line->descr[lineoff] = 0xF;
2183 line->w32[lineoff] = otag;
2184 }
2185 //// END inlined, specialised version of MC_(helperc_b_store4)
2186}
sewardj5d28efc2005-04-21 22:16:29 +00002187
njn1d0825f2006-03-27 11:37:07 +00002188static INLINE
2189void make_aligned_word32_noaccess ( Addr a )
sewardj5d28efc2005-04-21 22:16:29 +00002190{
njn1d0825f2006-03-27 11:37:07 +00002191 UWord sm_off;
sewardjae986ca2005-10-12 12:53:20 +00002192 SecMap* sm;
2193
sewardj5d28efc2005-04-21 22:16:29 +00002194 PROF_EVENT(310, "make_aligned_word32_noaccess");
2195
njn1d0825f2006-03-27 11:37:07 +00002196#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002197 MC_(make_mem_noaccess)(a, 4);
njn1d0825f2006-03-27 11:37:07 +00002198#else
bart5dd8e6a2008-03-22 08:04:29 +00002199 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
sewardj5d28efc2005-04-21 22:16:29 +00002200 PROF_EVENT(311, "make_aligned_word32_noaccess-slow1");
njndbf7ca72006-03-31 11:57:59 +00002201 MC_(make_mem_noaccess)(a, 4);
sewardj5d28efc2005-04-21 22:16:29 +00002202 return;
2203 }
2204
njna7c7ebd2006-03-28 12:51:02 +00002205 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002206 sm_off = SM_OFF(a);
2207 sm->vabits8[sm_off] = VA_BITS8_NOACCESS;
sewardj7cf4e6b2008-05-01 20:24:26 +00002208
2209 //// BEGIN inlined, specialised version of MC_(helperc_b_store4)
2210 //// Set the origins for a+0 .. a+3.
2211 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2212 OCacheLine* line;
2213 UWord lineoff = oc_line_offset(a);
2214 if (OC_ENABLE_ASSERTIONS) {
2215 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
2216 }
2217 line = find_OCacheLine( a );
2218 line->descr[lineoff] = 0;
2219 }
2220 //// END inlined, specialised version of MC_(helperc_b_store4)
njn1d0825f2006-03-27 11:37:07 +00002221#endif
sewardj5d28efc2005-04-21 22:16:29 +00002222}
2223
sewardj7cf4e6b2008-05-01 20:24:26 +00002224/*--------------------- 64-bit ---------------------*/
sewardj5d28efc2005-04-21 22:16:29 +00002225
njn9b007f62003-04-07 14:40:25 +00002226/* Nb: by "aligned" here we mean 8-byte aligned */
sewardj7cf4e6b2008-05-01 20:24:26 +00002227
2228static INLINE void make_aligned_word64_undefined ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002229{
njn1d0825f2006-03-27 11:37:07 +00002230 UWord sm_off16;
sewardjae986ca2005-10-12 12:53:20 +00002231 SecMap* sm;
2232
njndbf7ca72006-03-31 11:57:59 +00002233 PROF_EVENT(320, "make_aligned_word64_undefined");
sewardj23eb2fd2005-04-22 16:29:19 +00002234
njn1d0825f2006-03-27 11:37:07 +00002235#ifndef PERF_FAST_STACK2
sewardj7cf4e6b2008-05-01 20:24:26 +00002236 make_mem_undefined(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002237#else
bart5dd8e6a2008-03-22 08:04:29 +00002238 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
njndbf7ca72006-03-31 11:57:59 +00002239 PROF_EVENT(321, "make_aligned_word64_undefined-slow1");
sewardj7cf4e6b2008-05-01 20:24:26 +00002240 make_mem_undefined(a, 8);
sewardj23eb2fd2005-04-22 16:29:19 +00002241 return;
2242 }
2243
njna7c7ebd2006-03-28 12:51:02 +00002244 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002245 sm_off16 = SM_OFF_16(a);
njndbf7ca72006-03-31 11:57:59 +00002246 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00002247#endif
njn9b007f62003-04-07 14:40:25 +00002248}
2249
sewardj7cf4e6b2008-05-01 20:24:26 +00002250static INLINE
2251void make_aligned_word64_undefined_w_otag ( Addr a, UInt otag )
2252{
2253 make_aligned_word64_undefined(a);
2254 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2255 //// Set the origins for a+0 .. a+7
2256 { OCacheLine* line;
2257 UWord lineoff = oc_line_offset(a);
2258 tl_assert(lineoff >= 0
2259 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2260 line = find_OCacheLine( a );
2261 line->descr[lineoff+0] = 0xF;
2262 line->descr[lineoff+1] = 0xF;
2263 line->w32[lineoff+0] = otag;
2264 line->w32[lineoff+1] = otag;
2265 }
2266 //// END inlined, specialised version of MC_(helperc_b_store8)
2267}
sewardj23eb2fd2005-04-22 16:29:19 +00002268
njn1d0825f2006-03-27 11:37:07 +00002269static INLINE
2270void make_aligned_word64_noaccess ( Addr a )
njn9b007f62003-04-07 14:40:25 +00002271{
njn1d0825f2006-03-27 11:37:07 +00002272 UWord sm_off16;
sewardjae986ca2005-10-12 12:53:20 +00002273 SecMap* sm;
2274
sewardj23eb2fd2005-04-22 16:29:19 +00002275 PROF_EVENT(330, "make_aligned_word64_noaccess");
2276
njn1d0825f2006-03-27 11:37:07 +00002277#ifndef PERF_FAST_STACK2
njndbf7ca72006-03-31 11:57:59 +00002278 MC_(make_mem_noaccess)(a, 8);
njn1d0825f2006-03-27 11:37:07 +00002279#else
bart5dd8e6a2008-03-22 08:04:29 +00002280 if (UNLIKELY(a > MAX_PRIMARY_ADDRESS)) {
sewardj23eb2fd2005-04-22 16:29:19 +00002281 PROF_EVENT(331, "make_aligned_word64_noaccess-slow1");
njndbf7ca72006-03-31 11:57:59 +00002282 MC_(make_mem_noaccess)(a, 8);
sewardj23eb2fd2005-04-22 16:29:19 +00002283 return;
2284 }
2285
njna7c7ebd2006-03-28 12:51:02 +00002286 sm = get_secmap_for_writing_low(a);
njn1d0825f2006-03-27 11:37:07 +00002287 sm_off16 = SM_OFF_16(a);
2288 ((UShort*)(sm->vabits8))[sm_off16] = VA_BITS16_NOACCESS;
sewardj7cf4e6b2008-05-01 20:24:26 +00002289
2290 //// BEGIN inlined, specialised version of MC_(helperc_b_store8)
2291 //// Clear the origins for a+0 .. a+7.
2292 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
2293 OCacheLine* line;
2294 UWord lineoff = oc_line_offset(a);
2295 tl_assert(lineoff >= 0
2296 && lineoff < OC_W32S_PER_LINE -1/*'cos 8-aligned*/);
2297 line = find_OCacheLine( a );
2298 line->descr[lineoff+0] = 0;
2299 line->descr[lineoff+1] = 0;
2300 }
2301 //// END inlined, specialised version of MC_(helperc_b_store8)
njn1d0825f2006-03-27 11:37:07 +00002302#endif
njn9b007f62003-04-07 14:40:25 +00002303}
2304
sewardj23eb2fd2005-04-22 16:29:19 +00002305
njn1d0825f2006-03-27 11:37:07 +00002306/*------------------------------------------------------------*/
2307/*--- Stack pointer adjustment ---*/
2308/*------------------------------------------------------------*/
2309
sewardj7cf4e6b2008-05-01 20:24:26 +00002310/*--------------- adjustment by 4 bytes ---------------*/
2311
2312static void VG_REGPARM(2) mc_new_mem_stack_4_w_ECU(Addr new_SP, UInt ecu)
2313{
2314 UInt otag = ecu | MC_OKIND_STACK;
2315 PROF_EVENT(110, "new_mem_stack_4");
2316 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2317 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2318 } else {
2319 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 4, otag );
2320 }
2321}
2322
njn1d0825f2006-03-27 11:37:07 +00002323static void VG_REGPARM(1) mc_new_mem_stack_4(Addr new_SP)
2324{
2325 PROF_EVENT(110, "new_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002326 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002327 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njn1d0825f2006-03-27 11:37:07 +00002328 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002329 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 4 );
njn1d0825f2006-03-27 11:37:07 +00002330 }
2331}
2332
2333static void VG_REGPARM(1) mc_die_mem_stack_4(Addr new_SP)
2334{
2335 PROF_EVENT(120, "die_mem_stack_4");
sewardj05a46732006-10-17 01:28:10 +00002336 if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002337 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002338 } else {
njndbf7ca72006-03-31 11:57:59 +00002339 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-4, 4 );
njn1d0825f2006-03-27 11:37:07 +00002340 }
2341}
2342
sewardj7cf4e6b2008-05-01 20:24:26 +00002343/*--------------- adjustment by 8 bytes ---------------*/
2344
2345static void VG_REGPARM(2) mc_new_mem_stack_8_w_ECU(Addr new_SP, UInt ecu)
2346{
2347 UInt otag = ecu | MC_OKIND_STACK;
2348 PROF_EVENT(111, "new_mem_stack_8");
2349 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2350 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2351 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2352 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2353 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2354 } else {
2355 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 8, otag );
2356 }
2357}
2358
njn1d0825f2006-03-27 11:37:07 +00002359static void VG_REGPARM(1) mc_new_mem_stack_8(Addr new_SP)
2360{
2361 PROF_EVENT(111, "new_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002362 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002363 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
sewardj05a46732006-10-17 01:28:10 +00002364 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002365 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002366 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002367 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002368 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 8 );
njn1d0825f2006-03-27 11:37:07 +00002369 }
2370}
2371
2372static void VG_REGPARM(1) mc_die_mem_stack_8(Addr new_SP)
2373{
2374 PROF_EVENT(121, "die_mem_stack_8");
sewardj05a46732006-10-17 01:28:10 +00002375 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002376 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002377 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002378 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
2379 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002380 } else {
njndbf7ca72006-03-31 11:57:59 +00002381 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-8, 8 );
njn1d0825f2006-03-27 11:37:07 +00002382 }
2383}
2384
sewardj7cf4e6b2008-05-01 20:24:26 +00002385/*--------------- adjustment by 12 bytes ---------------*/
2386
2387static void VG_REGPARM(2) mc_new_mem_stack_12_w_ECU(Addr new_SP, UInt ecu)
2388{
2389 UInt otag = ecu | MC_OKIND_STACK;
2390 PROF_EVENT(112, "new_mem_stack_12");
2391 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2392 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2393 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2394 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2395 /* from previous test we don't have 8-alignment at offset +0,
2396 hence must have 8 alignment at offsets +4/-4. Hence safe to
2397 do 4 at +0 and then 8 at +4/. */
2398 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2399 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4, otag );
2400 } else {
2401 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 12, otag );
2402 }
2403}
2404
njn1d0825f2006-03-27 11:37:07 +00002405static void VG_REGPARM(1) mc_new_mem_stack_12(Addr new_SP)
2406{
2407 PROF_EVENT(112, "new_mem_stack_12");
sewardj05a46732006-10-17 01:28:10 +00002408 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002409 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002410 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002411 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002412 /* from previous test we don't have 8-alignment at offset +0,
2413 hence must have 8 alignment at offsets +4/-4. Hence safe to
2414 do 4 at +0 and then 8 at +4/. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002415 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002416 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njn1d0825f2006-03-27 11:37:07 +00002417 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002418 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 12 );
njn1d0825f2006-03-27 11:37:07 +00002419 }
2420}
2421
2422static void VG_REGPARM(1) mc_die_mem_stack_12(Addr new_SP)
2423{
2424 PROF_EVENT(122, "die_mem_stack_12");
2425 /* Note the -12 in the test */
sewardj43fcfd92006-10-17 23:14:42 +00002426 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP-12 )) {
2427 /* We have 8-alignment at -12, hence ok to do 8 at -12 and 4 at
2428 -4. */
njndbf7ca72006-03-31 11:57:59 +00002429 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2430 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
sewardj05a46732006-10-17 01:28:10 +00002431 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002432 /* We have 4-alignment at +0, but we don't have 8-alignment at
2433 -12. So we must have 8-alignment at -8. Hence do 4 at -12
2434 and then 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002435 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2436 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
njn1d0825f2006-03-27 11:37:07 +00002437 } else {
njndbf7ca72006-03-31 11:57:59 +00002438 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-12, 12 );
njn1d0825f2006-03-27 11:37:07 +00002439 }
2440}
2441
sewardj7cf4e6b2008-05-01 20:24:26 +00002442/*--------------- adjustment by 16 bytes ---------------*/
2443
2444static void VG_REGPARM(2) mc_new_mem_stack_16_w_ECU(Addr new_SP, UInt ecu)
2445{
2446 UInt otag = ecu | MC_OKIND_STACK;
2447 PROF_EVENT(113, "new_mem_stack_16");
2448 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2449 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
2450 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2451 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2452 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2453 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2454 Hence do 4 at +0, 8 at +4, 4 at +12. */
2455 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2456 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2457 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2458 } else {
2459 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 16, otag );
2460 }
2461}
2462
njn1d0825f2006-03-27 11:37:07 +00002463static void VG_REGPARM(1) mc_new_mem_stack_16(Addr new_SP)
2464{
2465 PROF_EVENT(113, "new_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002466 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002467 /* Have 8-alignment at +0, hence do 8 at +0 and 8 at +8. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002468 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002469 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
sewardj05a46732006-10-17 01:28:10 +00002470 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002471 /* Have 4 alignment at +0 but not 8; hence 8 must be at +4.
2472 Hence do 4 at +0, 8 at +4, 4 at +12. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002473 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
njndbf7ca72006-03-31 11:57:59 +00002474 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
2475 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
njn1d0825f2006-03-27 11:37:07 +00002476 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002477 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 16 );
njn1d0825f2006-03-27 11:37:07 +00002478 }
2479}
2480
2481static void VG_REGPARM(1) mc_die_mem_stack_16(Addr new_SP)
2482{
2483 PROF_EVENT(123, "die_mem_stack_16");
sewardj05a46732006-10-17 01:28:10 +00002484 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002485 /* Have 8-alignment at +0, hence do 8 at -16 and 8 at -8. */
njndbf7ca72006-03-31 11:57:59 +00002486 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2487 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-8 );
sewardj05a46732006-10-17 01:28:10 +00002488 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002489 /* 8 alignment must be at -12. Do 4 at -16, 8 at -12, 4 at -4. */
njndbf7ca72006-03-31 11:57:59 +00002490 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2491 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2492 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002493 } else {
njndbf7ca72006-03-31 11:57:59 +00002494 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-16, 16 );
njn1d0825f2006-03-27 11:37:07 +00002495 }
2496}
2497
sewardj7cf4e6b2008-05-01 20:24:26 +00002498/*--------------- adjustment by 32 bytes ---------------*/
2499
2500static void VG_REGPARM(2) mc_new_mem_stack_32_w_ECU(Addr new_SP, UInt ecu)
2501{
2502 UInt otag = ecu | MC_OKIND_STACK;
2503 PROF_EVENT(114, "new_mem_stack_32");
2504 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2505 /* Straightforward */
2506 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2507 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2508 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2509 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2510 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2511 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2512 +0,+28. */
2513 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2514 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+4 , otag );
2515 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+12, otag );
2516 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+20, otag );
2517 make_aligned_word32_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+28, otag );
2518 } else {
2519 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 32, otag );
2520 }
2521}
2522
njn1d0825f2006-03-27 11:37:07 +00002523static void VG_REGPARM(1) mc_new_mem_stack_32(Addr new_SP)
2524{
2525 PROF_EVENT(114, "new_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002526 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002527 /* Straightforward */
sewardj7cf4e6b2008-05-01 20:24:26 +00002528 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2529 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002530 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2531 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
sewardj05a46732006-10-17 01:28:10 +00002532 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002533 /* 8 alignment must be at +4. Hence do 8 at +4,+12,+20 and 4 at
2534 +0,+28. */
sewardj7cf4e6b2008-05-01 20:24:26 +00002535 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2536 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+4 );
njndbf7ca72006-03-31 11:57:59 +00002537 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+12 );
2538 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+20 );
2539 make_aligned_word32_undefined ( -VG_STACK_REDZONE_SZB + new_SP+28 );
njn1d0825f2006-03-27 11:37:07 +00002540 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002541 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 32 );
njn1d0825f2006-03-27 11:37:07 +00002542 }
2543}
2544
2545static void VG_REGPARM(1) mc_die_mem_stack_32(Addr new_SP)
2546{
2547 PROF_EVENT(124, "die_mem_stack_32");
sewardj05a46732006-10-17 01:28:10 +00002548 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002549 /* Straightforward */
njndbf7ca72006-03-31 11:57:59 +00002550 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2551 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2552 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2553 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
sewardj05a46732006-10-17 01:28:10 +00002554 } else if (VG_IS_4_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj43fcfd92006-10-17 23:14:42 +00002555 /* 8 alignment must be at -4 etc. Hence do 8 at -12,-20,-28 and
2556 4 at -32,-4. */
njndbf7ca72006-03-31 11:57:59 +00002557 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2558 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-28 );
2559 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-20 );
2560 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-12 );
2561 make_aligned_word32_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-4 );
njn1d0825f2006-03-27 11:37:07 +00002562 } else {
njndbf7ca72006-03-31 11:57:59 +00002563 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-32, 32 );
njn1d0825f2006-03-27 11:37:07 +00002564 }
2565}
2566
sewardj7cf4e6b2008-05-01 20:24:26 +00002567/*--------------- adjustment by 112 bytes ---------------*/
2568
2569static void VG_REGPARM(2) mc_new_mem_stack_112_w_ECU(Addr new_SP, UInt ecu)
2570{
2571 UInt otag = ecu | MC_OKIND_STACK;
2572 PROF_EVENT(115, "new_mem_stack_112");
2573 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2574 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2575 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2576 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2577 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2578 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2579 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2580 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2581 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2582 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2583 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2584 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2585 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2586 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2587 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2588 } else {
2589 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 112, otag );
2590 }
2591}
2592
njn1d0825f2006-03-27 11:37:07 +00002593static void VG_REGPARM(1) mc_new_mem_stack_112(Addr new_SP)
2594{
2595 PROF_EVENT(115, "new_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002596 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002597 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2598 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002599 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2600 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2601 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2602 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2603 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2604 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2605 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2606 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2607 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2608 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2609 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002610 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
njn1d0825f2006-03-27 11:37:07 +00002611 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002612 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 112 );
njn1d0825f2006-03-27 11:37:07 +00002613 }
2614}
2615
2616static void VG_REGPARM(1) mc_die_mem_stack_112(Addr new_SP)
2617{
2618 PROF_EVENT(125, "die_mem_stack_112");
sewardj05a46732006-10-17 01:28:10 +00002619 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002620 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2621 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2622 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2623 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2624 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2625 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2626 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2627 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2628 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2629 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2630 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2631 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2632 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2633 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002634 } else {
njndbf7ca72006-03-31 11:57:59 +00002635 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-112, 112 );
njn1d0825f2006-03-27 11:37:07 +00002636 }
2637}
2638
sewardj7cf4e6b2008-05-01 20:24:26 +00002639/*--------------- adjustment by 128 bytes ---------------*/
2640
2641static void VG_REGPARM(2) mc_new_mem_stack_128_w_ECU(Addr new_SP, UInt ecu)
2642{
2643 UInt otag = ecu | MC_OKIND_STACK;
2644 PROF_EVENT(116, "new_mem_stack_128");
2645 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2646 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP , otag );
2647 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8 , otag );
2648 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2649 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2650 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2651 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2652 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2653 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2654 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2655 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2656 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2657 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2658 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2659 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2660 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2661 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2662 } else {
2663 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 128, otag );
2664 }
2665}
2666
njn1d0825f2006-03-27 11:37:07 +00002667static void VG_REGPARM(1) mc_new_mem_stack_128(Addr new_SP)
2668{
2669 PROF_EVENT(116, "new_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002670 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002671 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2672 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002673 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2674 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2675 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2676 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2677 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2678 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2679 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2680 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2681 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2682 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2683 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002684 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2685 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2686 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
njn1d0825f2006-03-27 11:37:07 +00002687 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002688 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 128 );
njn1d0825f2006-03-27 11:37:07 +00002689 }
2690}
2691
2692static void VG_REGPARM(1) mc_die_mem_stack_128(Addr new_SP)
2693{
2694 PROF_EVENT(126, "die_mem_stack_128");
sewardj05a46732006-10-17 01:28:10 +00002695 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002696 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2697 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2698 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2699 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2700 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2701 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2702 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2703 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2704 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2705 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2706 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2707 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2708 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2709 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2710 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2711 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002712 } else {
njndbf7ca72006-03-31 11:57:59 +00002713 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-128, 128 );
njn1d0825f2006-03-27 11:37:07 +00002714 }
2715}
2716
sewardj7cf4e6b2008-05-01 20:24:26 +00002717/*--------------- adjustment by 144 bytes ---------------*/
2718
2719static void VG_REGPARM(2) mc_new_mem_stack_144_w_ECU(Addr new_SP, UInt ecu)
2720{
2721 UInt otag = ecu | MC_OKIND_STACK;
2722 PROF_EVENT(117, "new_mem_stack_144");
2723 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2724 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2725 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2726 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2727 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2728 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2729 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2730 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2731 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2732 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2733 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2734 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2735 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2736 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2737 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2738 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2739 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2740 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
2741 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
2742 } else {
2743 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 144, otag );
2744 }
2745}
2746
njn1d0825f2006-03-27 11:37:07 +00002747static void VG_REGPARM(1) mc_new_mem_stack_144(Addr new_SP)
2748{
2749 PROF_EVENT(117, "new_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00002750 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002751 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2752 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002753 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2754 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2755 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2756 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2757 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2758 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2759 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2760 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2761 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2762 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2763 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002764 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2765 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2766 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
2767 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
2768 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
njn1d0825f2006-03-27 11:37:07 +00002769 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002770 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 144 );
njn1d0825f2006-03-27 11:37:07 +00002771 }
2772}
2773
2774static void VG_REGPARM(1) mc_die_mem_stack_144(Addr new_SP)
2775{
2776 PROF_EVENT(127, "die_mem_stack_144");
sewardj05a46732006-10-17 01:28:10 +00002777 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002778 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
2779 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
2780 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2781 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2782 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2783 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2784 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2785 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2786 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2787 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2788 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2789 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2790 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2791 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2792 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2793 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2794 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2795 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002796 } else {
njndbf7ca72006-03-31 11:57:59 +00002797 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-144, 144 );
njn1d0825f2006-03-27 11:37:07 +00002798 }
2799}
2800
sewardj7cf4e6b2008-05-01 20:24:26 +00002801/*--------------- adjustment by 160 bytes ---------------*/
2802
2803static void VG_REGPARM(2) mc_new_mem_stack_160_w_ECU(Addr new_SP, UInt ecu)
2804{
2805 UInt otag = ecu | MC_OKIND_STACK;
2806 PROF_EVENT(118, "new_mem_stack_160");
2807 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
2808 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP, otag );
2809 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+8, otag );
2810 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+16, otag );
2811 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+24, otag );
2812 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+32, otag );
2813 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+40, otag );
2814 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+48, otag );
2815 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+56, otag );
2816 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+64, otag );
2817 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+72, otag );
2818 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+80, otag );
2819 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+88, otag );
2820 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+96, otag );
2821 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+104, otag );
2822 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+112, otag );
2823 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+120, otag );
2824 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+128, otag );
2825 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+136, otag );
2826 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+144, otag );
2827 make_aligned_word64_undefined_w_otag ( -VG_STACK_REDZONE_SZB + new_SP+152, otag );
2828 } else {
2829 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + new_SP, 160, otag );
2830 }
2831}
2832
njn1d0825f2006-03-27 11:37:07 +00002833static void VG_REGPARM(1) mc_new_mem_stack_160(Addr new_SP)
2834{
2835 PROF_EVENT(118, "new_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00002836 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00002837 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP );
2838 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+8 );
njndbf7ca72006-03-31 11:57:59 +00002839 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+16 );
2840 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+24 );
2841 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+32 );
2842 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+40 );
2843 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+48 );
2844 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+56 );
2845 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+64 );
2846 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+72 );
2847 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+80 );
2848 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+88 );
2849 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+96 );
sewardj7cf4e6b2008-05-01 20:24:26 +00002850 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+104 );
2851 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+112 );
2852 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+120 );
2853 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+128 );
2854 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+136 );
2855 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+144 );
2856 make_aligned_word64_undefined ( -VG_STACK_REDZONE_SZB + new_SP+152 );
njn1d0825f2006-03-27 11:37:07 +00002857 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00002858 make_mem_undefined ( -VG_STACK_REDZONE_SZB + new_SP, 160 );
njn1d0825f2006-03-27 11:37:07 +00002859 }
2860}
2861
2862static void VG_REGPARM(1) mc_die_mem_stack_160(Addr new_SP)
2863{
2864 PROF_EVENT(128, "die_mem_stack_160");
sewardj05a46732006-10-17 01:28:10 +00002865 if (VG_IS_8_ALIGNED( -VG_STACK_REDZONE_SZB + new_SP )) {
njndbf7ca72006-03-31 11:57:59 +00002866 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-160);
2867 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-152);
2868 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-144);
2869 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-136);
2870 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-128);
2871 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-120);
2872 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-112);
2873 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-104);
2874 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-96 );
2875 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-88 );
2876 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-80 );
2877 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-72 );
2878 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-64 );
2879 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-56 );
2880 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-48 );
2881 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-40 );
2882 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-32 );
2883 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-24 );
2884 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP-16 );
2885 make_aligned_word64_noaccess ( -VG_STACK_REDZONE_SZB + new_SP- 8 );
njn1d0825f2006-03-27 11:37:07 +00002886 } else {
njndbf7ca72006-03-31 11:57:59 +00002887 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + new_SP-160, 160 );
njn1d0825f2006-03-27 11:37:07 +00002888 }
2889}
2890
sewardj7cf4e6b2008-05-01 20:24:26 +00002891/*--------------- adjustment by N bytes ---------------*/
2892
2893static void mc_new_mem_stack_w_ECU ( Addr a, SizeT len, UInt ecu )
2894{
2895 UInt otag = ecu | MC_OKIND_STACK;
2896 PROF_EVENT(115, "new_mem_stack_w_otag");
2897 MC_(make_mem_undefined_w_otag) ( -VG_STACK_REDZONE_SZB + a, len, otag );
2898}
2899
njn1d0825f2006-03-27 11:37:07 +00002900static void mc_new_mem_stack ( Addr a, SizeT len )
2901{
2902 PROF_EVENT(115, "new_mem_stack");
sewardj7cf4e6b2008-05-01 20:24:26 +00002903 make_mem_undefined ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00002904}
2905
2906static void mc_die_mem_stack ( Addr a, SizeT len )
2907{
2908 PROF_EVENT(125, "die_mem_stack");
njndbf7ca72006-03-31 11:57:59 +00002909 MC_(make_mem_noaccess) ( -VG_STACK_REDZONE_SZB + a, len );
njn1d0825f2006-03-27 11:37:07 +00002910}
njn9b007f62003-04-07 14:40:25 +00002911
sewardj45d94cc2005-04-20 14:44:11 +00002912
njn1d0825f2006-03-27 11:37:07 +00002913/* The AMD64 ABI says:
2914
2915 "The 128-byte area beyond the location pointed to by %rsp is considered
2916 to be reserved and shall not be modified by signal or interrupt
2917 handlers. Therefore, functions may use this area for temporary data
2918 that is not needed across function calls. In particular, leaf functions
2919 may use this area for their entire stack frame, rather than adjusting
2920 the stack pointer in the prologue and epilogue. This area is known as
2921 red zone [sic]."
2922
2923 So after any call or return we need to mark this redzone as containing
2924 undefined values.
2925
2926 Consider this: we're in function f. f calls g. g moves rsp down
2927 modestly (say 16 bytes) and writes stuff all over the red zone, making it
2928 defined. g returns. f is buggy and reads from parts of the red zone
2929 that it didn't write on. But because g filled that area in, f is going
2930 to be picking up defined V bits and so any errors from reading bits of
2931 the red zone it didn't write, will be missed. The only solution I could
2932 think of was to make the red zone undefined when g returns to f.
2933
2934 This is in accordance with the ABI, which makes it clear the redzone
2935 is volatile across function calls.
2936
2937 The problem occurs the other way round too: f could fill the RZ up
2938 with defined values and g could mistakenly read them. So the RZ
2939 also needs to be nuked on function calls.
2940*/
sewardj7cf4e6b2008-05-01 20:24:26 +00002941
2942
2943/* Here's a simple cache to hold nia -> ECU mappings. It could be
2944 improved so as to have a lower miss rate. */
2945
2946static UWord stats__nia_cache_queries = 0;
2947static UWord stats__nia_cache_misses = 0;
2948
2949typedef
2950 struct { UWord nia0; UWord ecu0; /* nia0 maps to ecu0 */
2951 UWord nia1; UWord ecu1; } /* nia1 maps to ecu1 */
2952 WCacheEnt;
2953
2954#define N_NIA_TO_ECU_CACHE 511
2955
2956static WCacheEnt nia_to_ecu_cache[N_NIA_TO_ECU_CACHE];
2957
2958static void init_nia_to_ecu_cache ( void )
sewardj826ec492005-05-12 18:05:00 +00002959{
sewardj7cf4e6b2008-05-01 20:24:26 +00002960 UWord i;
2961 Addr zero_addr = 0;
2962 ExeContext* zero_ec;
2963 UInt zero_ecu;
2964 /* Fill all the slots with an entry for address zero, and the
2965 relevant otags accordingly. Hence the cache is initially filled
2966 with valid data. */
2967 zero_ec = VG_(make_depth_1_ExeContext_from_Addr)(zero_addr);
2968 tl_assert(zero_ec);
2969 zero_ecu = VG_(get_ECU_from_ExeContext)(zero_ec);
2970 tl_assert(VG_(is_plausible_ECU)(zero_ecu));
2971 for (i = 0; i < N_NIA_TO_ECU_CACHE; i++) {
2972 nia_to_ecu_cache[i].nia0 = zero_addr;
2973 nia_to_ecu_cache[i].ecu0 = zero_ecu;
2974 nia_to_ecu_cache[i].nia1 = zero_addr;
2975 nia_to_ecu_cache[i].ecu1 = zero_ecu;
2976 }
2977}
2978
2979static inline UInt convert_nia_to_ecu ( Addr nia )
2980{
2981 UWord i;
2982 UInt ecu;
2983 ExeContext* ec;
2984
2985 tl_assert( sizeof(nia_to_ecu_cache[0].nia1) == sizeof(nia) );
2986
2987 stats__nia_cache_queries++;
2988 i = nia % N_NIA_TO_ECU_CACHE;
2989 tl_assert(i >= 0 && i < N_NIA_TO_ECU_CACHE);
2990
2991 if (LIKELY( nia_to_ecu_cache[i].nia0 == nia ))
2992 return nia_to_ecu_cache[i].ecu0;
2993
2994 if (LIKELY( nia_to_ecu_cache[i].nia1 == nia )) {
2995# define SWAP(_w1,_w2) { UWord _t = _w1; _w1 = _w2; _w2 = _t; }
2996 SWAP( nia_to_ecu_cache[i].nia0, nia_to_ecu_cache[i].nia1 );
2997 SWAP( nia_to_ecu_cache[i].ecu0, nia_to_ecu_cache[i].ecu1 );
2998# undef SWAP
2999 return nia_to_ecu_cache[i].ecu0;
3000 }
3001
3002 stats__nia_cache_misses++;
3003 ec = VG_(make_depth_1_ExeContext_from_Addr)(nia);
3004 tl_assert(ec);
3005 ecu = VG_(get_ECU_from_ExeContext)(ec);
3006 tl_assert(VG_(is_plausible_ECU)(ecu));
3007
3008 nia_to_ecu_cache[i].nia1 = nia_to_ecu_cache[i].nia0;
3009 nia_to_ecu_cache[i].ecu1 = nia_to_ecu_cache[i].ecu0;
3010
3011 nia_to_ecu_cache[i].nia0 = nia;
3012 nia_to_ecu_cache[i].ecu0 = (UWord)ecu;
3013 return ecu;
3014}
3015
3016
3017/* Note that this serves both the origin-tracking and
3018 no-origin-tracking modes. We assume that calls to it are
3019 sufficiently infrequent that it isn't worth specialising for the
3020 with/without origin-tracking cases. */
3021void MC_(helperc_MAKE_STACK_UNINIT) ( Addr base, UWord len, Addr nia )
3022{
3023 UInt otag;
sewardj826ec492005-05-12 18:05:00 +00003024 tl_assert(sizeof(UWord) == sizeof(SizeT));
sewardj2a3a1a72005-05-12 23:25:43 +00003025 if (0)
sewardj7cf4e6b2008-05-01 20:24:26 +00003026 VG_(printf)("helperc_MAKE_STACK_UNINIT (%p,%lu,nia=%p)\n",
3027 base, len, nia );
3028
3029 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3030 UInt ecu = convert_nia_to_ecu ( nia );
3031 tl_assert(VG_(is_plausible_ECU)(ecu));
3032 otag = ecu | MC_OKIND_STACK;
3033 } else {
3034 tl_assert(nia == 0);
3035 otag = 0;
3036 }
sewardj2a3a1a72005-05-12 23:25:43 +00003037
3038# if 0
3039 /* Really slow version */
sewardj7cf4e6b2008-05-01 20:24:26 +00003040 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003041# endif
3042
3043# if 0
3044 /* Slow(ish) version, which is fairly easily seen to be correct.
3045 */
bart5dd8e6a2008-03-22 08:04:29 +00003046 if (LIKELY( VG_IS_8_ALIGNED(base) && len==128 )) {
sewardj7cf4e6b2008-05-01 20:24:26 +00003047 make_aligned_word64_undefined(base + 0, otag);
3048 make_aligned_word64_undefined(base + 8, otag);
3049 make_aligned_word64_undefined(base + 16, otag);
3050 make_aligned_word64_undefined(base + 24, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003051
sewardj7cf4e6b2008-05-01 20:24:26 +00003052 make_aligned_word64_undefined(base + 32, otag);
3053 make_aligned_word64_undefined(base + 40, otag);
3054 make_aligned_word64_undefined(base + 48, otag);
3055 make_aligned_word64_undefined(base + 56, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003056
sewardj7cf4e6b2008-05-01 20:24:26 +00003057 make_aligned_word64_undefined(base + 64, otag);
3058 make_aligned_word64_undefined(base + 72, otag);
3059 make_aligned_word64_undefined(base + 80, otag);
3060 make_aligned_word64_undefined(base + 88, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003061
sewardj7cf4e6b2008-05-01 20:24:26 +00003062 make_aligned_word64_undefined(base + 96, otag);
3063 make_aligned_word64_undefined(base + 104, otag);
3064 make_aligned_word64_undefined(base + 112, otag);
3065 make_aligned_word64_undefined(base + 120, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003066 } else {
sewardj7cf4e6b2008-05-01 20:24:26 +00003067 MC_(make_mem_undefined)(base, len, otag);
sewardj2a3a1a72005-05-12 23:25:43 +00003068 }
3069# endif
3070
3071 /* Idea is: go fast when
3072 * 8-aligned and length is 128
3073 * the sm is available in the main primary map
njn1d0825f2006-03-27 11:37:07 +00003074 * the address range falls entirely with a single secondary map
3075 If all those conditions hold, just update the V+A bits by writing
3076 directly into the vabits array. (If the sm was distinguished, this
3077 will make a copy and then write to it.)
sewardj2a3a1a72005-05-12 23:25:43 +00003078 */
sewardj7cf4e6b2008-05-01 20:24:26 +00003079
bart5dd8e6a2008-03-22 08:04:29 +00003080 if (LIKELY( len == 128 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003081 /* Now we know the address range is suitably sized and aligned. */
3082 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003083 UWord a_hi = (UWord)(base + 128 - 1);
njn1d0825f2006-03-27 11:37:07 +00003084 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003085 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003086 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003087 SecMap* sm = get_secmap_for_writing_low(a_lo);
3088 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2a3a1a72005-05-12 23:25:43 +00003089 /* Now we know that the entire address range falls within a
3090 single secondary map, and that that secondary 'lives' in
3091 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003092 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003093 // Finally, we know that the range is entirely within one secmap.
3094 UWord v_off = SM_OFF(a_lo);
3095 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003096 p[ 0] = VA_BITS16_UNDEFINED;
3097 p[ 1] = VA_BITS16_UNDEFINED;
3098 p[ 2] = VA_BITS16_UNDEFINED;
3099 p[ 3] = VA_BITS16_UNDEFINED;
3100 p[ 4] = VA_BITS16_UNDEFINED;
3101 p[ 5] = VA_BITS16_UNDEFINED;
3102 p[ 6] = VA_BITS16_UNDEFINED;
3103 p[ 7] = VA_BITS16_UNDEFINED;
3104 p[ 8] = VA_BITS16_UNDEFINED;
3105 p[ 9] = VA_BITS16_UNDEFINED;
3106 p[10] = VA_BITS16_UNDEFINED;
3107 p[11] = VA_BITS16_UNDEFINED;
3108 p[12] = VA_BITS16_UNDEFINED;
3109 p[13] = VA_BITS16_UNDEFINED;
3110 p[14] = VA_BITS16_UNDEFINED;
3111 p[15] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003112 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3113 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3114 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3115 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3116 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3117 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3118 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3119 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3120 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3121 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3122 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3123 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3124 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3125 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3126 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3127 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3128 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3129 }
sewardj2a3a1a72005-05-12 23:25:43 +00003130 return;
njn1d0825f2006-03-27 11:37:07 +00003131 }
sewardj2a3a1a72005-05-12 23:25:43 +00003132 }
3133 }
3134
sewardj2e1a6772006-01-18 04:16:27 +00003135 /* 288 bytes (36 ULongs) is the magic value for ELF ppc64. */
bart5dd8e6a2008-03-22 08:04:29 +00003136 if (LIKELY( len == 288 && VG_IS_8_ALIGNED(base) )) {
njn1d0825f2006-03-27 11:37:07 +00003137 /* Now we know the address range is suitably sized and aligned. */
3138 UWord a_lo = (UWord)(base);
sewardj3f5f5562006-06-16 21:39:08 +00003139 UWord a_hi = (UWord)(base + 288 - 1);
njn1d0825f2006-03-27 11:37:07 +00003140 tl_assert(a_lo < a_hi); // paranoia: detect overflow
sewardj7244e712008-05-02 12:35:48 +00003141 if (a_hi <= MAX_PRIMARY_ADDRESS) {
njn1d0825f2006-03-27 11:37:07 +00003142 // Now we know the entire range is within the main primary map.
njna7c7ebd2006-03-28 12:51:02 +00003143 SecMap* sm = get_secmap_for_writing_low(a_lo);
3144 SecMap* sm_hi = get_secmap_for_writing_low(a_hi);
sewardj2e1a6772006-01-18 04:16:27 +00003145 /* Now we know that the entire address range falls within a
3146 single secondary map, and that that secondary 'lives' in
3147 the main primary map. */
bart5dd8e6a2008-03-22 08:04:29 +00003148 if (LIKELY(sm == sm_hi)) {
njn1d0825f2006-03-27 11:37:07 +00003149 // Finally, we know that the range is entirely within one secmap.
3150 UWord v_off = SM_OFF(a_lo);
3151 UShort* p = (UShort*)(&sm->vabits8[v_off]);
njndbf7ca72006-03-31 11:57:59 +00003152 p[ 0] = VA_BITS16_UNDEFINED;
3153 p[ 1] = VA_BITS16_UNDEFINED;
3154 p[ 2] = VA_BITS16_UNDEFINED;
3155 p[ 3] = VA_BITS16_UNDEFINED;
3156 p[ 4] = VA_BITS16_UNDEFINED;
3157 p[ 5] = VA_BITS16_UNDEFINED;
3158 p[ 6] = VA_BITS16_UNDEFINED;
3159 p[ 7] = VA_BITS16_UNDEFINED;
3160 p[ 8] = VA_BITS16_UNDEFINED;
3161 p[ 9] = VA_BITS16_UNDEFINED;
3162 p[10] = VA_BITS16_UNDEFINED;
3163 p[11] = VA_BITS16_UNDEFINED;
3164 p[12] = VA_BITS16_UNDEFINED;
3165 p[13] = VA_BITS16_UNDEFINED;
3166 p[14] = VA_BITS16_UNDEFINED;
3167 p[15] = VA_BITS16_UNDEFINED;
3168 p[16] = VA_BITS16_UNDEFINED;
3169 p[17] = VA_BITS16_UNDEFINED;
3170 p[18] = VA_BITS16_UNDEFINED;
3171 p[19] = VA_BITS16_UNDEFINED;
3172 p[20] = VA_BITS16_UNDEFINED;
3173 p[21] = VA_BITS16_UNDEFINED;
3174 p[22] = VA_BITS16_UNDEFINED;
3175 p[23] = VA_BITS16_UNDEFINED;
3176 p[24] = VA_BITS16_UNDEFINED;
3177 p[25] = VA_BITS16_UNDEFINED;
3178 p[26] = VA_BITS16_UNDEFINED;
3179 p[27] = VA_BITS16_UNDEFINED;
3180 p[28] = VA_BITS16_UNDEFINED;
3181 p[29] = VA_BITS16_UNDEFINED;
3182 p[30] = VA_BITS16_UNDEFINED;
3183 p[31] = VA_BITS16_UNDEFINED;
3184 p[32] = VA_BITS16_UNDEFINED;
3185 p[33] = VA_BITS16_UNDEFINED;
3186 p[34] = VA_BITS16_UNDEFINED;
3187 p[35] = VA_BITS16_UNDEFINED;
sewardj7cf4e6b2008-05-01 20:24:26 +00003188 if (UNLIKELY( MC_(clo_mc_level) == 3 )) {
3189 set_aligned_word64_Origin_to_undef( base + 8 * 0, otag );
3190 set_aligned_word64_Origin_to_undef( base + 8 * 1, otag );
3191 set_aligned_word64_Origin_to_undef( base + 8 * 2, otag );
3192 set_aligned_word64_Origin_to_undef( base + 8 * 3, otag );
3193 set_aligned_word64_Origin_to_undef( base + 8 * 4, otag );
3194 set_aligned_word64_Origin_to_undef( base + 8 * 5, otag );
3195 set_aligned_word64_Origin_to_undef( base + 8 * 6, otag );
3196 set_aligned_word64_Origin_to_undef( base + 8 * 7, otag );
3197 set_aligned_word64_Origin_to_undef( base + 8 * 8, otag );
3198 set_aligned_word64_Origin_to_undef( base + 8 * 9, otag );
3199 set_aligned_word64_Origin_to_undef( base + 8 * 10, otag );
3200 set_aligned_word64_Origin_to_undef( base + 8 * 11, otag );
3201 set_aligned_word64_Origin_to_undef( base + 8 * 12, otag );
3202 set_aligned_word64_Origin_to_undef( base + 8 * 13, otag );
3203 set_aligned_word64_Origin_to_undef( base + 8 * 14, otag );
3204 set_aligned_word64_Origin_to_undef( base + 8 * 15, otag );
3205 set_aligned_word64_Origin_to_undef( base + 8 * 16, otag );
3206 set_aligned_word64_Origin_to_undef( base + 8 * 17, otag );
3207 set_aligned_word64_Origin_to_undef( base + 8 * 18, otag );
3208 set_aligned_word64_Origin_to_undef( base + 8 * 19, otag );
3209 set_aligned_word64_Origin_to_undef( base + 8 * 20, otag );
3210 set_aligned_word64_Origin_to_undef( base + 8 * 21, otag );
3211 set_aligned_word64_Origin_to_undef( base + 8 * 22, otag );
3212 set_aligned_word64_Origin_to_undef( base + 8 * 23, otag );
3213 set_aligned_word64_Origin_to_undef( base + 8 * 24, otag );
3214 set_aligned_word64_Origin_to_undef( base + 8 * 25, otag );
3215 set_aligned_word64_Origin_to_undef( base + 8 * 26, otag );
3216 set_aligned_word64_Origin_to_undef( base + 8 * 27, otag );
3217 set_aligned_word64_Origin_to_undef( base + 8 * 28, otag );
3218 set_aligned_word64_Origin_to_undef( base + 8 * 29, otag );
3219 set_aligned_word64_Origin_to_undef( base + 8 * 30, otag );
3220 set_aligned_word64_Origin_to_undef( base + 8 * 31, otag );
3221 set_aligned_word64_Origin_to_undef( base + 8 * 32, otag );
3222 set_aligned_word64_Origin_to_undef( base + 8 * 33, otag );
3223 set_aligned_word64_Origin_to_undef( base + 8 * 34, otag );
3224 set_aligned_word64_Origin_to_undef( base + 8 * 35, otag );
3225 }
sewardj2e1a6772006-01-18 04:16:27 +00003226 return;
njn1d0825f2006-03-27 11:37:07 +00003227 }
sewardj2e1a6772006-01-18 04:16:27 +00003228 }
3229 }
3230
sewardj2a3a1a72005-05-12 23:25:43 +00003231 /* else fall into slow case */
sewardj7cf4e6b2008-05-01 20:24:26 +00003232 MC_(make_mem_undefined_w_otag)(base, len, otag);
sewardj826ec492005-05-12 18:05:00 +00003233}
3234
3235
nethercote8b76fe52004-11-08 19:20:09 +00003236/*------------------------------------------------------------*/
3237/*--- Checking memory ---*/
3238/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00003239
sewardje4ccc012005-05-02 12:53:38 +00003240typedef
3241 enum {
3242 MC_Ok = 5,
3243 MC_AddrErr = 6,
3244 MC_ValueErr = 7
3245 }
3246 MC_ReadResult;
3247
3248
njn25e49d8e72002-09-23 09:36:25 +00003249/* Check permissions for address range. If inadequate permissions
3250 exist, *bad_addr is set to the offending address, so the caller can
3251 know what it is. */
3252
sewardjecf8e102003-07-12 12:11:39 +00003253/* Returns True if [a .. a+len) is not addressible. Otherwise,
3254 returns False, and if bad_addr is non-NULL, sets *bad_addr to
3255 indicate the lowest failing address. Functions below are
3256 similar. */
njndbf7ca72006-03-31 11:57:59 +00003257Bool MC_(check_mem_is_noaccess) ( Addr a, SizeT len, Addr* bad_addr )
sewardjecf8e102003-07-12 12:11:39 +00003258{
nethercote451eae92004-11-02 13:06:32 +00003259 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003260 UWord vabits2;
3261
njndbf7ca72006-03-31 11:57:59 +00003262 PROF_EVENT(60, "check_mem_is_noaccess");
sewardjecf8e102003-07-12 12:11:39 +00003263 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003264 PROF_EVENT(61, "check_mem_is_noaccess(loop)");
njn1d0825f2006-03-27 11:37:07 +00003265 vabits2 = get_vabits2(a);
3266 if (VA_BITS2_NOACCESS != vabits2) {
3267 if (bad_addr != NULL) *bad_addr = a;
sewardjecf8e102003-07-12 12:11:39 +00003268 return False;
3269 }
3270 a++;
3271 }
3272 return True;
3273}
3274
sewardj7cf4e6b2008-05-01 20:24:26 +00003275static Bool is_mem_addressable ( Addr a, SizeT len,
3276 /*OUT*/Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +00003277{
nethercote451eae92004-11-02 13:06:32 +00003278 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003279 UWord vabits2;
3280
njndbf7ca72006-03-31 11:57:59 +00003281 PROF_EVENT(62, "is_mem_addressable");
njn25e49d8e72002-09-23 09:36:25 +00003282 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003283 PROF_EVENT(63, "is_mem_addressable(loop)");
njn1d0825f2006-03-27 11:37:07 +00003284 vabits2 = get_vabits2(a);
3285 if (VA_BITS2_NOACCESS == vabits2) {
njn25e49d8e72002-09-23 09:36:25 +00003286 if (bad_addr != NULL) *bad_addr = a;
3287 return False;
3288 }
3289 a++;
3290 }
3291 return True;
3292}
3293
sewardj7cf4e6b2008-05-01 20:24:26 +00003294static MC_ReadResult is_mem_defined ( Addr a, SizeT len,
3295 /*OUT*/Addr* bad_addr,
3296 /*OUT*/UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003297{
nethercote451eae92004-11-02 13:06:32 +00003298 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00003299 UWord vabits2;
njn25e49d8e72002-09-23 09:36:25 +00003300
njndbf7ca72006-03-31 11:57:59 +00003301 PROF_EVENT(64, "is_mem_defined");
3302 DEBUG("is_mem_defined\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003303
3304 if (otag) *otag = 0;
3305 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003306 for (i = 0; i < len; i++) {
njndbf7ca72006-03-31 11:57:59 +00003307 PROF_EVENT(65, "is_mem_defined(loop)");
njn1d0825f2006-03-27 11:37:07 +00003308 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003309 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003310 // Error! Nb: Report addressability errors in preference to
3311 // definedness errors. And don't report definedeness errors unless
3312 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003313 if (bad_addr) {
3314 *bad_addr = a;
3315 }
3316 if (VA_BITS2_NOACCESS == vabits2) {
3317 return MC_AddrErr;
3318 }
3319 if (MC_(clo_mc_level) >= 2) {
3320 if (otag && MC_(clo_mc_level) == 3) {
3321 *otag = MC_(helperc_b_load1)( a );
3322 }
3323 return MC_ValueErr;
3324 }
njn25e49d8e72002-09-23 09:36:25 +00003325 }
3326 a++;
3327 }
nethercote8b76fe52004-11-08 19:20:09 +00003328 return MC_Ok;
njn25e49d8e72002-09-23 09:36:25 +00003329}
3330
3331
3332/* Check a zero-terminated ascii string. Tricky -- don't want to
3333 examine the actual bytes, to find the end, until we're sure it is
3334 safe to do so. */
3335
sewardj7cf4e6b2008-05-01 20:24:26 +00003336static Bool mc_is_defined_asciiz ( Addr a, Addr* bad_addr, UInt* otag )
njn25e49d8e72002-09-23 09:36:25 +00003337{
njn1d0825f2006-03-27 11:37:07 +00003338 UWord vabits2;
3339
njndbf7ca72006-03-31 11:57:59 +00003340 PROF_EVENT(66, "mc_is_defined_asciiz");
3341 DEBUG("mc_is_defined_asciiz\n");
sewardj7cf4e6b2008-05-01 20:24:26 +00003342
3343 if (otag) *otag = 0;
3344 if (bad_addr) *bad_addr = 0;
njn25e49d8e72002-09-23 09:36:25 +00003345 while (True) {
njndbf7ca72006-03-31 11:57:59 +00003346 PROF_EVENT(67, "mc_is_defined_asciiz(loop)");
njn1d0825f2006-03-27 11:37:07 +00003347 vabits2 = get_vabits2(a);
njndbf7ca72006-03-31 11:57:59 +00003348 if (VA_BITS2_DEFINED != vabits2) {
njn1d0825f2006-03-27 11:37:07 +00003349 // Error! Nb: Report addressability errors in preference to
3350 // definedness errors. And don't report definedeness errors unless
3351 // --undef-value-errors=yes.
sewardj7cf4e6b2008-05-01 20:24:26 +00003352 if (bad_addr) {
3353 *bad_addr = a;
3354 }
3355 if (VA_BITS2_NOACCESS == vabits2) {
3356 return MC_AddrErr;
3357 }
3358 if (MC_(clo_mc_level) >= 2) {
3359 if (otag && MC_(clo_mc_level) == 3) {
3360 *otag = MC_(helperc_b_load1)( a );
3361 }
3362 return MC_ValueErr;
3363 }
njn25e49d8e72002-09-23 09:36:25 +00003364 }
3365 /* Ok, a is safe to read. */
njn1d0825f2006-03-27 11:37:07 +00003366 if (* ((UChar*)a) == 0) {
sewardj45d94cc2005-04-20 14:44:11 +00003367 return MC_Ok;
njn1d0825f2006-03-27 11:37:07 +00003368 }
njn25e49d8e72002-09-23 09:36:25 +00003369 a++;
3370 }
3371}
3372
3373
3374/*------------------------------------------------------------*/
3375/*--- Memory event handlers ---*/
3376/*------------------------------------------------------------*/
3377
njn25e49d8e72002-09-23 09:36:25 +00003378static
njndbf7ca72006-03-31 11:57:59 +00003379void check_mem_is_addressable ( CorePart part, ThreadId tid, Char* s,
3380 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003381{
njn25e49d8e72002-09-23 09:36:25 +00003382 Addr bad_addr;
njndbf7ca72006-03-31 11:57:59 +00003383 Bool ok = is_mem_addressable ( base, size, &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003384
njn25e49d8e72002-09-23 09:36:25 +00003385 if (!ok) {
3386 switch (part) {
3387 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003388 MC_(record_memparam_error) ( tid, bad_addr,
3389 /*isAddrErr*/True, s, 0/*otag*/ );
njn25e49d8e72002-09-23 09:36:25 +00003390 break;
3391
njn25e49d8e72002-09-23 09:36:25 +00003392 case Vg_CoreSignal:
sewardj7ce71662008-05-02 10:33:15 +00003393 MC_(record_core_mem_error)( tid, /*isAddrErr*/True, s );
njn25e49d8e72002-09-23 09:36:25 +00003394 break;
3395
3396 default:
njndbf7ca72006-03-31 11:57:59 +00003397 VG_(tool_panic)("check_mem_is_addressable: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003398 }
3399 }
njn25e49d8e72002-09-23 09:36:25 +00003400}
3401
3402static
njndbf7ca72006-03-31 11:57:59 +00003403void check_mem_is_defined ( CorePart part, ThreadId tid, Char* s,
nethercote451eae92004-11-02 13:06:32 +00003404 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +00003405{
sewardj7cf4e6b2008-05-01 20:24:26 +00003406 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003407 Addr bad_addr;
sewardj7cf4e6b2008-05-01 20:24:26 +00003408 MC_ReadResult res = is_mem_defined ( base, size, &bad_addr, &otag );
sewardj45f4e7c2005-09-27 19:20:21 +00003409
nethercote8b76fe52004-11-08 19:20:09 +00003410 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003411 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj45f4e7c2005-09-27 19:20:21 +00003412
njn25e49d8e72002-09-23 09:36:25 +00003413 switch (part) {
3414 case Vg_CoreSysCall:
sewardj7ce71662008-05-02 10:33:15 +00003415 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3416 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003417 break;
3418
njn25e49d8e72002-09-23 09:36:25 +00003419 /* If we're being asked to jump to a silly address, record an error
3420 message before potentially crashing the entire system. */
3421 case Vg_CoreTranslate:
sewardj7ce71662008-05-02 10:33:15 +00003422 MC_(record_jump_error)( tid, bad_addr );
njn25e49d8e72002-09-23 09:36:25 +00003423 break;
3424
3425 default:
njndbf7ca72006-03-31 11:57:59 +00003426 VG_(tool_panic)("check_mem_is_defined: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +00003427 }
3428 }
njn25e49d8e72002-09-23 09:36:25 +00003429}
3430
3431static
njndbf7ca72006-03-31 11:57:59 +00003432void check_mem_is_defined_asciiz ( CorePart part, ThreadId tid,
njn5c004e42002-11-18 11:04:50 +00003433 Char* s, Addr str )
njn25e49d8e72002-09-23 09:36:25 +00003434{
nethercote8b76fe52004-11-08 19:20:09 +00003435 MC_ReadResult res;
njn5ab96ac2005-05-08 02:59:50 +00003436 Addr bad_addr = 0; // shut GCC up
sewardj7cf4e6b2008-05-01 20:24:26 +00003437 UInt otag = 0;
njn25e49d8e72002-09-23 09:36:25 +00003438
njnca82cc02004-11-22 17:18:48 +00003439 tl_assert(part == Vg_CoreSysCall);
sewardj7cf4e6b2008-05-01 20:24:26 +00003440 res = mc_is_defined_asciiz ( (Addr)str, &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00003441 if (MC_Ok != res) {
njn718d3b12006-12-16 00:54:12 +00003442 Bool isAddrErr = ( MC_AddrErr == res ? True : False );
sewardj7ce71662008-05-02 10:33:15 +00003443 MC_(record_memparam_error) ( tid, bad_addr, isAddrErr, s,
3444 isAddrErr ? 0 : otag );
njn25e49d8e72002-09-23 09:36:25 +00003445 }
njn25e49d8e72002-09-23 09:36:25 +00003446}
3447
njn25e49d8e72002-09-23 09:36:25 +00003448static
nethercote451eae92004-11-02 13:06:32 +00003449void mc_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00003450{
njndbf7ca72006-03-31 11:57:59 +00003451 /* Ignore the permissions, just make it defined. Seems to work... */
njnba7b4582006-09-21 15:59:30 +00003452 // Because code is defined, initialised variables get put in the data
3453 // segment and are defined, and uninitialised variables get put in the
3454 // bss segment and are auto-zeroed (and so defined).
3455 //
3456 // It's possible that there will be padding between global variables.
3457 // This will also be auto-zeroed, and marked as defined by Memcheck. If
3458 // a program uses it, Memcheck will not complain. This is arguably a
3459 // false negative, but it's a grey area -- the behaviour is defined (the
3460 // padding is zeroed) but it's probably not what the user intended. And
3461 // we can't avoid it.
nethercote451eae92004-11-02 13:06:32 +00003462 DEBUG("mc_new_mem_startup(%p, %llu, rr=%u, ww=%u, xx=%u)\n",
njndbf7ca72006-03-31 11:57:59 +00003463 a, (ULong)len, rr, ww, xx);
3464 MC_(make_mem_defined)(a, len);
njn25e49d8e72002-09-23 09:36:25 +00003465}
3466
3467static
njnb8dca862005-03-14 02:42:44 +00003468void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +00003469{
njndbf7ca72006-03-31 11:57:59 +00003470 MC_(make_mem_defined)(a, len);
njn25e49d8e72002-09-23 09:36:25 +00003471}
3472
njncf45fd42004-11-24 16:30:22 +00003473static
3474void mc_post_mem_write(CorePart part, ThreadId tid, Addr a, SizeT len)
3475{
njndbf7ca72006-03-31 11:57:59 +00003476 MC_(make_mem_defined)(a, len);
njncf45fd42004-11-24 16:30:22 +00003477}
njn25e49d8e72002-09-23 09:36:25 +00003478
sewardj45d94cc2005-04-20 14:44:11 +00003479
njn25e49d8e72002-09-23 09:36:25 +00003480/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00003481/*--- Register event handlers ---*/
3482/*------------------------------------------------------------*/
3483
sewardj7cf4e6b2008-05-01 20:24:26 +00003484/* Try and get a nonzero origin for the guest state section of thread
3485 tid characterised by (offset,size). Return 0 if nothing to show
3486 for it. */
3487static UInt mb_get_origin_for_guest_offset ( ThreadId tid,
3488 Int offset, SizeT size )
3489{
3490 Int sh2off;
3491 UChar area[6];
3492 UInt otag;
3493 sh2off = MC_(get_otrack_shadow_offset)( offset, size );
3494 if (sh2off == -1)
3495 return 0; /* This piece of guest state is not tracked */
3496 tl_assert(sh2off >= 0);
3497 tl_assert(0 == (sh2off % 4));
3498 area[0] = 0x31;
3499 area[5] = 0x27;
3500 VG_(get_shadow_regs_area)( tid, &area[1], 2/*shadowno*/,sh2off,4 );
3501 tl_assert(area[0] == 0x31);
3502 tl_assert(area[5] == 0x27);
3503 otag = *(UInt*)&area[1];
3504 return otag;
3505}
3506
3507
sewardj45d94cc2005-04-20 14:44:11 +00003508/* When some chunk of guest state is written, mark the corresponding
3509 shadow area as valid. This is used to initialise arbitrarily large
sewardj62eae5f2006-01-17 01:58:24 +00003510 chunks of guest state, hence the _SIZE value, which has to be as
3511 big as the biggest guest state.
sewardj45d94cc2005-04-20 14:44:11 +00003512*/
3513static void mc_post_reg_write ( CorePart part, ThreadId tid,
3514 OffT offset, SizeT size)
njnd3040452003-05-19 15:04:06 +00003515{
sewardj05a46732006-10-17 01:28:10 +00003516# define MAX_REG_WRITE_SIZE 1408
cerion21082042005-12-06 19:07:08 +00003517 UChar area[MAX_REG_WRITE_SIZE];
3518 tl_assert(size <= MAX_REG_WRITE_SIZE);
njn1d0825f2006-03-27 11:37:07 +00003519 VG_(memset)(area, V_BITS8_DEFINED, size);
sewardj7cf4e6b2008-05-01 20:24:26 +00003520 VG_(set_shadow_regs_area)( tid, 1/*shadowNo*/,offset,size, area );
cerion21082042005-12-06 19:07:08 +00003521# undef MAX_REG_WRITE_SIZE
njnd3040452003-05-19 15:04:06 +00003522}
3523
sewardj45d94cc2005-04-20 14:44:11 +00003524static
3525void mc_post_reg_write_clientcall ( ThreadId tid,
3526 OffT offset, SizeT size,
3527 Addr f)
njnd3040452003-05-19 15:04:06 +00003528{
njncf45fd42004-11-24 16:30:22 +00003529 mc_post_reg_write(/*dummy*/0, tid, offset, size);
njnd3040452003-05-19 15:04:06 +00003530}
3531
sewardj45d94cc2005-04-20 14:44:11 +00003532/* Look at the definedness of the guest's shadow state for
3533 [offset, offset+len). If any part of that is undefined, record
3534 a parameter error.
3535*/
3536static void mc_pre_reg_read ( CorePart part, ThreadId tid, Char* s,
3537 OffT offset, SizeT size)
nethercote8b76fe52004-11-08 19:20:09 +00003538{
sewardj45d94cc2005-04-20 14:44:11 +00003539 Int i;
3540 Bool bad;
sewardj7cf4e6b2008-05-01 20:24:26 +00003541 UInt otag;
sewardj45d94cc2005-04-20 14:44:11 +00003542
3543 UChar area[16];
3544 tl_assert(size <= 16);
3545
sewardj7cf4e6b2008-05-01 20:24:26 +00003546 VG_(get_shadow_regs_area)( tid, area, 1/*shadowNo*/,offset,size );
sewardj45d94cc2005-04-20 14:44:11 +00003547
3548 bad = False;
3549 for (i = 0; i < size; i++) {
njn1d0825f2006-03-27 11:37:07 +00003550 if (area[i] != V_BITS8_DEFINED) {
sewardj2c27f702005-05-03 18:19:05 +00003551 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00003552 break;
3553 }
nethercote8b76fe52004-11-08 19:20:09 +00003554 }
3555
sewardj7cf4e6b2008-05-01 20:24:26 +00003556 if (!bad)
3557 return;
3558
3559 /* We've found some undefinedness. See if we can also find an
3560 origin for it. */
3561 otag = mb_get_origin_for_guest_offset( tid, offset, size );
sewardj7ce71662008-05-02 10:33:15 +00003562 MC_(record_regparam_error) ( tid, s, otag );
nethercote8b76fe52004-11-08 19:20:09 +00003563}
njnd3040452003-05-19 15:04:06 +00003564
njn25e49d8e72002-09-23 09:36:25 +00003565
sewardj6cf40ff2005-04-20 22:31:26 +00003566/*------------------------------------------------------------*/
sewardjc859fbf2005-04-22 21:10:28 +00003567/*--- Functions called directly from generated code: ---*/
3568/*--- Load/store handlers. ---*/
sewardj6cf40ff2005-04-20 22:31:26 +00003569/*------------------------------------------------------------*/
3570
njn1d0825f2006-03-27 11:37:07 +00003571/* Types: LOADV32, LOADV16, LOADV8 are:
sewardj6cf40ff2005-04-20 22:31:26 +00003572 UWord fn ( Addr a )
3573 so they return 32-bits on 32-bit machines and 64-bits on
3574 64-bit machines. Addr has the same size as a host word.
3575
njn1d0825f2006-03-27 11:37:07 +00003576 LOADV64 is always ULong fn ( Addr a )
sewardj6cf40ff2005-04-20 22:31:26 +00003577
njn1d0825f2006-03-27 11:37:07 +00003578 Similarly for STOREV8, STOREV16, STOREV32, the supplied vbits
3579 are a UWord, and for STOREV64 they are a ULong.
sewardj6cf40ff2005-04-20 22:31:26 +00003580*/
3581
sewardj7244e712008-05-02 12:35:48 +00003582/* If any part of '_a' indicated by the mask is 1, either '_a' is not
3583 naturally '_sz/8'-aligned, or it exceeds the range covered by the
3584 primary map. This is all very tricky (and important!), so let's
3585 work through the maths by hand (below), *and* assert for these
3586 values at startup. */
3587#define MASK(_szInBytes) \
3588 ( ~((0x10000UL-(_szInBytes)) | ((N_PRIMARY_MAP-1) << 16)) )
3589
3590/* MASK only exists so as to define this macro. */
3591#define UNALIGNED_OR_HIGH(_a,_szInBits) \
3592 ((_a) & MASK((_szInBits>>3)))
3593
3594/* On a 32-bit machine:
3595
3596 N_PRIMARY_BITS == 16, so
3597 N_PRIMARY_MAP == 0x10000, so
3598 N_PRIMARY_MAP-1 == 0xFFFF, so
3599 (N_PRIMARY_MAP-1) << 16 == 0xFFFF0000, and so
3600
3601 MASK(1) = ~ ( (0x10000 - 1) | 0xFFFF0000 )
3602 = ~ ( 0xFFFF | 0xFFFF0000 )
3603 = ~ 0xFFFF'FFFF
3604 = 0
3605
3606 MASK(2) = ~ ( (0x10000 - 2) | 0xFFFF0000 )
3607 = ~ ( 0xFFFE | 0xFFFF0000 )
3608 = ~ 0xFFFF'FFFE
3609 = 1
3610
3611 MASK(4) = ~ ( (0x10000 - 4) | 0xFFFF0000 )
3612 = ~ ( 0xFFFC | 0xFFFF0000 )
3613 = ~ 0xFFFF'FFFC
3614 = 3
3615
3616 MASK(8) = ~ ( (0x10000 - 8) | 0xFFFF0000 )
3617 = ~ ( 0xFFF8 | 0xFFFF0000 )
3618 = ~ 0xFFFF'FFF8
3619 = 7
3620
3621 Hence in the 32-bit case, "a & MASK(1/2/4/8)" is a nonzero value
3622 precisely when a is not 1/2/4/8-bytes aligned. And obviously, for
3623 the 1-byte alignment case, it is always a zero value, since MASK(1)
3624 is zero. All as expected.
3625
3626 On a 64-bit machine, it's more complex, since we're testing
3627 simultaneously for misalignment and for the address being at or
3628 above 32G:
3629
3630 N_PRIMARY_BITS == 19, so
3631 N_PRIMARY_MAP == 0x80000, so
3632 N_PRIMARY_MAP-1 == 0x7FFFF, so
3633 (N_PRIMARY_MAP-1) << 16 == 0x7FFFF'0000, and so
3634
3635 MASK(1) = ~ ( (0x10000 - 1) | 0x7FFFF'0000 )
3636 = ~ ( 0xFFFF | 0x7FFFF'0000 )
3637 = ~ 0x7FFFF'FFFF
3638 = 0xFFFF'FFF8'0000'0000
3639
3640 MASK(2) = ~ ( (0x10000 - 2) | 0x7FFFF'0000 )
3641 = ~ ( 0xFFFE | 0x7FFFF'0000 )
3642 = ~ 0x7FFFF'FFFE
3643 = 0xFFFF'FFF8'0000'0001
3644
3645 MASK(4) = ~ ( (0x10000 - 4) | 0x7FFFF'0000 )
3646 = ~ ( 0xFFFC | 0x7FFFF'0000 )
3647 = ~ 0x7FFFF'FFFC
3648 = 0xFFFF'FFF8'0000'0003
3649
3650 MASK(8) = ~ ( (0x10000 - 8) | 0x7FFFF'0000 )
3651 = ~ ( 0xFFF8 | 0x7FFFF'0000 )
3652 = ~ 0x7FFFF'FFF8
3653 = 0xFFFF'FFF8'0000'0007
3654*/
njn1d0825f2006-03-27 11:37:07 +00003655
3656
sewardj95448072004-11-22 20:19:51 +00003657/* ------------------------ Size = 8 ------------------------ */
3658
njn1d0825f2006-03-27 11:37:07 +00003659static INLINE
3660ULong mc_LOADV64 ( Addr a, Bool isBigEndian )
3661{
3662 UWord sm_off16, vabits16;
3663 SecMap* sm;
3664
3665 PROF_EVENT(200, "mc_LOADV64");
3666
3667#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003668 return mc_LOADVn_slow( a, 64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003669#else
bart5dd8e6a2008-03-22 08:04:29 +00003670 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
njn1d0825f2006-03-27 11:37:07 +00003671 PROF_EVENT(201, "mc_LOADV64-slow1");
njn45e81252006-03-28 12:35:08 +00003672 return (ULong)mc_LOADVn_slow( a, 64, isBigEndian );
sewardjf9d81612005-04-23 23:25:49 +00003673 }
3674
njna7c7ebd2006-03-28 12:51:02 +00003675 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003676 sm_off16 = SM_OFF_16(a);
3677 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3678
3679 // Handle common case quickly: a is suitably aligned, is mapped, and
3680 // addressible.
3681 // Convert V bits from compact memory form to expanded register form.
bart5dd8e6a2008-03-22 08:04:29 +00003682 if (LIKELY(vabits16 == VA_BITS16_DEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00003683 return V_BITS64_DEFINED;
bart5dd8e6a2008-03-22 08:04:29 +00003684 } else if (LIKELY(vabits16 == VA_BITS16_UNDEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00003685 return V_BITS64_UNDEFINED;
3686 } else {
njndbf7ca72006-03-31 11:57:59 +00003687 /* Slow case: the 8 bytes are not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00003688 PROF_EVENT(202, "mc_LOADV64-slow2");
njn45e81252006-03-28 12:35:08 +00003689 return mc_LOADVn_slow( a, 64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003690 }
3691#endif
3692}
3693
3694VG_REGPARM(1) ULong MC_(helperc_LOADV64be) ( Addr a )
3695{
3696 return mc_LOADV64(a, True);
3697}
3698VG_REGPARM(1) ULong MC_(helperc_LOADV64le) ( Addr a )
3699{
3700 return mc_LOADV64(a, False);
3701}
sewardjf9d81612005-04-23 23:25:49 +00003702
sewardjf9d81612005-04-23 23:25:49 +00003703
njn1d0825f2006-03-27 11:37:07 +00003704static INLINE
njn4cf530b2006-04-06 13:33:48 +00003705void mc_STOREV64 ( Addr a, ULong vbits64, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00003706{
3707 UWord sm_off16, vabits16;
3708 SecMap* sm;
3709
3710 PROF_EVENT(210, "mc_STOREV64");
3711
3712#ifndef PERF_FAST_STOREV
3713 // XXX: this slow case seems to be marginally faster than the fast case!
3714 // Investigate further.
njn4cf530b2006-04-06 13:33:48 +00003715 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003716#else
bart5dd8e6a2008-03-22 08:04:29 +00003717 if (UNLIKELY( UNALIGNED_OR_HIGH(a,64) )) {
njn1d0825f2006-03-27 11:37:07 +00003718 PROF_EVENT(211, "mc_STOREV64-slow1");
njn4cf530b2006-04-06 13:33:48 +00003719 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003720 return;
sewardjf9d81612005-04-23 23:25:49 +00003721 }
3722
njna7c7ebd2006-03-28 12:51:02 +00003723 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003724 sm_off16 = SM_OFF_16(a);
3725 vabits16 = ((UShort*)(sm->vabits8))[sm_off16];
3726
bart5dd8e6a2008-03-22 08:04:29 +00003727 if (LIKELY( !is_distinguished_sm(sm) &&
njndbf7ca72006-03-31 11:57:59 +00003728 (VA_BITS16_DEFINED == vabits16 ||
3729 VA_BITS16_UNDEFINED == vabits16) ))
njn1d0825f2006-03-27 11:37:07 +00003730 {
3731 /* Handle common case quickly: a is suitably aligned, */
3732 /* is mapped, and is addressible. */
3733 // Convert full V-bits in register to compact 2-bit form.
njn4cf530b2006-04-06 13:33:48 +00003734 if (V_BITS64_DEFINED == vbits64) {
njndbf7ca72006-03-31 11:57:59 +00003735 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_DEFINED;
njn4cf530b2006-04-06 13:33:48 +00003736 } else if (V_BITS64_UNDEFINED == vbits64) {
njndbf7ca72006-03-31 11:57:59 +00003737 ((UShort*)(sm->vabits8))[sm_off16] = (UShort)VA_BITS16_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00003738 } else {
3739 /* Slow but general case -- writing partially defined bytes. */
3740 PROF_EVENT(212, "mc_STOREV64-slow2");
njn4cf530b2006-04-06 13:33:48 +00003741 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003742 }
3743 } else {
3744 /* Slow but general case. */
3745 PROF_EVENT(213, "mc_STOREV64-slow3");
njn4cf530b2006-04-06 13:33:48 +00003746 mc_STOREVn_slow( a, 64, vbits64, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003747 }
3748#endif
3749}
3750
njn4cf530b2006-04-06 13:33:48 +00003751VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00003752{
njn4cf530b2006-04-06 13:33:48 +00003753 mc_STOREV64(a, vbits64, True);
njn1d0825f2006-03-27 11:37:07 +00003754}
njn4cf530b2006-04-06 13:33:48 +00003755VG_REGPARM(1) void MC_(helperc_STOREV64le) ( Addr a, ULong vbits64 )
njn1d0825f2006-03-27 11:37:07 +00003756{
njn4cf530b2006-04-06 13:33:48 +00003757 mc_STOREV64(a, vbits64, False);
njn1d0825f2006-03-27 11:37:07 +00003758}
sewardj95448072004-11-22 20:19:51 +00003759
sewardj95448072004-11-22 20:19:51 +00003760
3761/* ------------------------ Size = 4 ------------------------ */
3762
njn1d0825f2006-03-27 11:37:07 +00003763static INLINE
3764UWord mc_LOADV32 ( Addr a, Bool isBigEndian )
3765{
3766 UWord sm_off, vabits8;
3767 SecMap* sm;
3768
3769 PROF_EVENT(220, "mc_LOADV32");
3770
3771#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003772 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003773#else
bart5dd8e6a2008-03-22 08:04:29 +00003774 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
njn1d0825f2006-03-27 11:37:07 +00003775 PROF_EVENT(221, "mc_LOADV32-slow1");
njn45e81252006-03-28 12:35:08 +00003776 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
sewardjc1a2cda2005-04-21 17:34:00 +00003777 }
3778
njna7c7ebd2006-03-28 12:51:02 +00003779 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003780 sm_off = SM_OFF(a);
3781 vabits8 = sm->vabits8[sm_off];
3782
3783 // Handle common case quickly: a is suitably aligned, is mapped, and the
3784 // entire word32 it lives in is addressible.
3785 // Convert V bits from compact memory form to expanded register form.
3786 // For 64-bit platforms, set the high 32 bits of retval to 1 (undefined).
3787 // Almost certainly not necessary, but be paranoid.
bart5dd8e6a2008-03-22 08:04:29 +00003788 if (LIKELY(vabits8 == VA_BITS8_DEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00003789 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_DEFINED);
bart5dd8e6a2008-03-22 08:04:29 +00003790 } else if (LIKELY(vabits8 == VA_BITS8_UNDEFINED)) {
njn1d0825f2006-03-27 11:37:07 +00003791 return ((UWord)0xFFFFFFFF00000000ULL | (UWord)V_BITS32_UNDEFINED);
3792 } else {
njndbf7ca72006-03-31 11:57:59 +00003793 /* Slow case: the 4 bytes are not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00003794 PROF_EVENT(222, "mc_LOADV32-slow2");
njn45e81252006-03-28 12:35:08 +00003795 return (UWord)mc_LOADVn_slow( a, 32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003796 }
3797#endif
3798}
3799
3800VG_REGPARM(1) UWord MC_(helperc_LOADV32be) ( Addr a )
3801{
3802 return mc_LOADV32(a, True);
3803}
3804VG_REGPARM(1) UWord MC_(helperc_LOADV32le) ( Addr a )
3805{
3806 return mc_LOADV32(a, False);
3807}
sewardjc1a2cda2005-04-21 17:34:00 +00003808
sewardjc1a2cda2005-04-21 17:34:00 +00003809
njn1d0825f2006-03-27 11:37:07 +00003810static INLINE
njn4cf530b2006-04-06 13:33:48 +00003811void mc_STOREV32 ( Addr a, UWord vbits32, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00003812{
3813 UWord sm_off, vabits8;
3814 SecMap* sm;
3815
3816 PROF_EVENT(230, "mc_STOREV32");
3817
3818#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00003819 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003820#else
bart5dd8e6a2008-03-22 08:04:29 +00003821 if (UNLIKELY( UNALIGNED_OR_HIGH(a,32) )) {
njn1d0825f2006-03-27 11:37:07 +00003822 PROF_EVENT(231, "mc_STOREV32-slow1");
njn4cf530b2006-04-06 13:33:48 +00003823 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003824 return;
sewardjc1a2cda2005-04-21 17:34:00 +00003825 }
3826
njna7c7ebd2006-03-28 12:51:02 +00003827 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003828 sm_off = SM_OFF(a);
3829 vabits8 = sm->vabits8[sm_off];
3830
njn1d0825f2006-03-27 11:37:07 +00003831 // Cleverness: sometimes we don't have to write the shadow memory at
3832 // all, if we can tell that what we want to write is the same as what is
sewardjb6a4ece2008-05-03 05:24:57 +00003833 // already there. The 64/16/8 bit cases also have cleverness at this
3834 // point, but it works a little differently to the code below.
njn4cf530b2006-04-06 13:33:48 +00003835 if (V_BITS32_DEFINED == vbits32) {
njndbf7ca72006-03-31 11:57:59 +00003836 if (vabits8 == (UInt)VA_BITS8_DEFINED) {
njn1d0825f2006-03-27 11:37:07 +00003837 return;
njndbf7ca72006-03-31 11:57:59 +00003838 } else if (!is_distinguished_sm(sm) && VA_BITS8_UNDEFINED == vabits8) {
3839 sm->vabits8[sm_off] = (UInt)VA_BITS8_DEFINED;
njn1d0825f2006-03-27 11:37:07 +00003840 } else {
njndbf7ca72006-03-31 11:57:59 +00003841 // not defined/undefined, or distinguished and changing state
njn1d0825f2006-03-27 11:37:07 +00003842 PROF_EVENT(232, "mc_STOREV32-slow2");
njn4cf530b2006-04-06 13:33:48 +00003843 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003844 }
njn4cf530b2006-04-06 13:33:48 +00003845 } else if (V_BITS32_UNDEFINED == vbits32) {
njndbf7ca72006-03-31 11:57:59 +00003846 if (vabits8 == (UInt)VA_BITS8_UNDEFINED) {
njn1d0825f2006-03-27 11:37:07 +00003847 return;
njndbf7ca72006-03-31 11:57:59 +00003848 } else if (!is_distinguished_sm(sm) && VA_BITS8_DEFINED == vabits8) {
3849 sm->vabits8[sm_off] = (UInt)VA_BITS8_UNDEFINED;
njn1d0825f2006-03-27 11:37:07 +00003850 } else {
njndbf7ca72006-03-31 11:57:59 +00003851 // not defined/undefined, or distinguished and changing state
njn1d0825f2006-03-27 11:37:07 +00003852 PROF_EVENT(233, "mc_STOREV32-slow3");
njn4cf530b2006-04-06 13:33:48 +00003853 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003854 }
3855 } else {
3856 // Partially defined word
3857 PROF_EVENT(234, "mc_STOREV32-slow4");
njn4cf530b2006-04-06 13:33:48 +00003858 mc_STOREVn_slow( a, 32, (ULong)vbits32, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003859 }
njn1d0825f2006-03-27 11:37:07 +00003860#endif
3861}
3862
njn4cf530b2006-04-06 13:33:48 +00003863VG_REGPARM(2) void MC_(helperc_STOREV32be) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00003864{
njn4cf530b2006-04-06 13:33:48 +00003865 mc_STOREV32(a, vbits32, True);
njn1d0825f2006-03-27 11:37:07 +00003866}
njn4cf530b2006-04-06 13:33:48 +00003867VG_REGPARM(2) void MC_(helperc_STOREV32le) ( Addr a, UWord vbits32 )
njn1d0825f2006-03-27 11:37:07 +00003868{
njn4cf530b2006-04-06 13:33:48 +00003869 mc_STOREV32(a, vbits32, False);
njn1d0825f2006-03-27 11:37:07 +00003870}
njn25e49d8e72002-09-23 09:36:25 +00003871
njn25e49d8e72002-09-23 09:36:25 +00003872
sewardj95448072004-11-22 20:19:51 +00003873/* ------------------------ Size = 2 ------------------------ */
3874
njn1d0825f2006-03-27 11:37:07 +00003875static INLINE
3876UWord mc_LOADV16 ( Addr a, Bool isBigEndian )
3877{
3878 UWord sm_off, vabits8;
3879 SecMap* sm;
3880
3881 PROF_EVENT(240, "mc_LOADV16");
3882
3883#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003884 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003885#else
bart5dd8e6a2008-03-22 08:04:29 +00003886 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
njn1d0825f2006-03-27 11:37:07 +00003887 PROF_EVENT(241, "mc_LOADV16-slow1");
njn45e81252006-03-28 12:35:08 +00003888 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
sewardjc1a2cda2005-04-21 17:34:00 +00003889 }
3890
njna7c7ebd2006-03-28 12:51:02 +00003891 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003892 sm_off = SM_OFF(a);
3893 vabits8 = sm->vabits8[sm_off];
3894 // Handle common case quickly: a is suitably aligned, is mapped, and is
3895 // addressible.
3896 // Convert V bits from compact memory form to expanded register form
njndbf7ca72006-03-31 11:57:59 +00003897 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS16_DEFINED; }
3898 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS16_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00003899 else {
njndbf7ca72006-03-31 11:57:59 +00003900 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
njn1d0825f2006-03-27 11:37:07 +00003901 // the two sub-bytes.
3902 UChar vabits4 = extract_vabits4_from_vabits8(a, vabits8);
njndbf7ca72006-03-31 11:57:59 +00003903 if (vabits4 == VA_BITS4_DEFINED ) { return V_BITS16_DEFINED; }
3904 else if (vabits4 == VA_BITS4_UNDEFINED) { return V_BITS16_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00003905 else {
njndbf7ca72006-03-31 11:57:59 +00003906 /* Slow case: the two bytes are not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00003907 PROF_EVENT(242, "mc_LOADV16-slow2");
njn45e81252006-03-28 12:35:08 +00003908 return (UWord)mc_LOADVn_slow( a, 16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003909 }
3910 }
3911#endif
3912}
3913
3914VG_REGPARM(1) UWord MC_(helperc_LOADV16be) ( Addr a )
3915{
3916 return mc_LOADV16(a, True);
3917}
3918VG_REGPARM(1) UWord MC_(helperc_LOADV16le) ( Addr a )
3919{
3920 return mc_LOADV16(a, False);
3921}
sewardjc1a2cda2005-04-21 17:34:00 +00003922
sewardjc1a2cda2005-04-21 17:34:00 +00003923
njn1d0825f2006-03-27 11:37:07 +00003924static INLINE
njn4cf530b2006-04-06 13:33:48 +00003925void mc_STOREV16 ( Addr a, UWord vbits16, Bool isBigEndian )
njn1d0825f2006-03-27 11:37:07 +00003926{
3927 UWord sm_off, vabits8;
3928 SecMap* sm;
3929
3930 PROF_EVENT(250, "mc_STOREV16");
3931
3932#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00003933 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003934#else
bart5dd8e6a2008-03-22 08:04:29 +00003935 if (UNLIKELY( UNALIGNED_OR_HIGH(a,16) )) {
njn1d0825f2006-03-27 11:37:07 +00003936 PROF_EVENT(251, "mc_STOREV16-slow1");
njn4cf530b2006-04-06 13:33:48 +00003937 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003938 return;
sewardjc1a2cda2005-04-21 17:34:00 +00003939 }
3940
njna7c7ebd2006-03-28 12:51:02 +00003941 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00003942 sm_off = SM_OFF(a);
3943 vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00003944 if (LIKELY( !is_distinguished_sm(sm) &&
njndbf7ca72006-03-31 11:57:59 +00003945 (VA_BITS8_DEFINED == vabits8 ||
3946 VA_BITS8_UNDEFINED == vabits8) ))
njn1d0825f2006-03-27 11:37:07 +00003947 {
3948 /* Handle common case quickly: a is suitably aligned, */
3949 /* is mapped, and is addressible. */
3950 // Convert full V-bits in register to compact 2-bit form.
njn4cf530b2006-04-06 13:33:48 +00003951 if (V_BITS16_DEFINED == vbits16) {
njndbf7ca72006-03-31 11:57:59 +00003952 insert_vabits4_into_vabits8( a, VA_BITS4_DEFINED ,
njn1d0825f2006-03-27 11:37:07 +00003953 &(sm->vabits8[sm_off]) );
njn4cf530b2006-04-06 13:33:48 +00003954 } else if (V_BITS16_UNDEFINED == vbits16) {
njndbf7ca72006-03-31 11:57:59 +00003955 insert_vabits4_into_vabits8( a, VA_BITS4_UNDEFINED,
njn1d0825f2006-03-27 11:37:07 +00003956 &(sm->vabits8[sm_off]) );
3957 } else {
3958 /* Slow but general case -- writing partially defined bytes. */
3959 PROF_EVENT(252, "mc_STOREV16-slow2");
njn4cf530b2006-04-06 13:33:48 +00003960 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003961 }
3962 } else {
3963 /* Slow but general case. */
3964 PROF_EVENT(253, "mc_STOREV16-slow3");
njn4cf530b2006-04-06 13:33:48 +00003965 mc_STOREVn_slow( a, 16, (ULong)vbits16, isBigEndian );
njn1d0825f2006-03-27 11:37:07 +00003966 }
3967#endif
3968}
njn25e49d8e72002-09-23 09:36:25 +00003969
njn4cf530b2006-04-06 13:33:48 +00003970VG_REGPARM(2) void MC_(helperc_STOREV16be) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00003971{
njn4cf530b2006-04-06 13:33:48 +00003972 mc_STOREV16(a, vbits16, True);
njn1d0825f2006-03-27 11:37:07 +00003973}
njn4cf530b2006-04-06 13:33:48 +00003974VG_REGPARM(2) void MC_(helperc_STOREV16le) ( Addr a, UWord vbits16 )
njn1d0825f2006-03-27 11:37:07 +00003975{
njn4cf530b2006-04-06 13:33:48 +00003976 mc_STOREV16(a, vbits16, False);
njn1d0825f2006-03-27 11:37:07 +00003977}
sewardj5d28efc2005-04-21 22:16:29 +00003978
njn25e49d8e72002-09-23 09:36:25 +00003979
sewardj95448072004-11-22 20:19:51 +00003980/* ------------------------ Size = 1 ------------------------ */
sewardj8cf88b72005-07-08 01:29:33 +00003981/* Note: endianness is irrelevant for size == 1 */
sewardj95448072004-11-22 20:19:51 +00003982
njnaf839f52005-06-23 03:27:57 +00003983VG_REGPARM(1)
njn1d0825f2006-03-27 11:37:07 +00003984UWord MC_(helperc_LOADV8) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00003985{
njn1d0825f2006-03-27 11:37:07 +00003986 UWord sm_off, vabits8;
sewardjae986ca2005-10-12 12:53:20 +00003987 SecMap* sm;
3988
njn1d0825f2006-03-27 11:37:07 +00003989 PROF_EVENT(260, "mc_LOADV8");
sewardjc1a2cda2005-04-21 17:34:00 +00003990
njn1d0825f2006-03-27 11:37:07 +00003991#ifndef PERF_FAST_LOADV
njn45e81252006-03-28 12:35:08 +00003992 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00003993#else
bart5dd8e6a2008-03-22 08:04:29 +00003994 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
njn1d0825f2006-03-27 11:37:07 +00003995 PROF_EVENT(261, "mc_LOADV8-slow1");
njn45e81252006-03-28 12:35:08 +00003996 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
sewardjc1a2cda2005-04-21 17:34:00 +00003997 }
3998
njna7c7ebd2006-03-28 12:51:02 +00003999 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00004000 sm_off = SM_OFF(a);
4001 vabits8 = sm->vabits8[sm_off];
4002 // Convert V bits from compact memory form to expanded register form
4003 // Handle common case quickly: a is mapped, and the entire
4004 // word32 it lives in is addressible.
njndbf7ca72006-03-31 11:57:59 +00004005 if (vabits8 == VA_BITS8_DEFINED ) { return V_BITS8_DEFINED; }
4006 else if (vabits8 == VA_BITS8_UNDEFINED) { return V_BITS8_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00004007 else {
njndbf7ca72006-03-31 11:57:59 +00004008 // The 4 (yes, 4) bytes are not all-defined or all-undefined, check
njn1d0825f2006-03-27 11:37:07 +00004009 // the single byte.
4010 UChar vabits2 = extract_vabits2_from_vabits8(a, vabits8);
njndbf7ca72006-03-31 11:57:59 +00004011 if (vabits2 == VA_BITS2_DEFINED ) { return V_BITS8_DEFINED; }
4012 else if (vabits2 == VA_BITS2_UNDEFINED) { return V_BITS8_UNDEFINED; }
njn1d0825f2006-03-27 11:37:07 +00004013 else {
njndbf7ca72006-03-31 11:57:59 +00004014 /* Slow case: the byte is not all-defined or all-undefined. */
njn1d0825f2006-03-27 11:37:07 +00004015 PROF_EVENT(262, "mc_LOADV8-slow2");
njn45e81252006-03-28 12:35:08 +00004016 return (UWord)mc_LOADVn_slow( a, 8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004017 }
sewardjc1a2cda2005-04-21 17:34:00 +00004018 }
njn1d0825f2006-03-27 11:37:07 +00004019#endif
njn25e49d8e72002-09-23 09:36:25 +00004020}
4021
sewardjc1a2cda2005-04-21 17:34:00 +00004022
njnaf839f52005-06-23 03:27:57 +00004023VG_REGPARM(2)
njn4cf530b2006-04-06 13:33:48 +00004024void MC_(helperc_STOREV8) ( Addr a, UWord vbits8 )
njn25e49d8e72002-09-23 09:36:25 +00004025{
njn1d0825f2006-03-27 11:37:07 +00004026 UWord sm_off, vabits8;
sewardjae986ca2005-10-12 12:53:20 +00004027 SecMap* sm;
4028
njn1d0825f2006-03-27 11:37:07 +00004029 PROF_EVENT(270, "mc_STOREV8");
sewardjc1a2cda2005-04-21 17:34:00 +00004030
njn1d0825f2006-03-27 11:37:07 +00004031#ifndef PERF_FAST_STOREV
njn4cf530b2006-04-06 13:33:48 +00004032 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004033#else
bart5dd8e6a2008-03-22 08:04:29 +00004034 if (UNLIKELY( UNALIGNED_OR_HIGH(a,8) )) {
njn1d0825f2006-03-27 11:37:07 +00004035 PROF_EVENT(271, "mc_STOREV8-slow1");
njn4cf530b2006-04-06 13:33:48 +00004036 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
sewardjc1a2cda2005-04-21 17:34:00 +00004037 return;
4038 }
4039
njna7c7ebd2006-03-28 12:51:02 +00004040 sm = get_secmap_for_reading_low(a);
njn1d0825f2006-03-27 11:37:07 +00004041 sm_off = SM_OFF(a);
4042 vabits8 = sm->vabits8[sm_off];
bart5dd8e6a2008-03-22 08:04:29 +00004043 if (LIKELY
njn1d0825f2006-03-27 11:37:07 +00004044 ( !is_distinguished_sm(sm) &&
njndbf7ca72006-03-31 11:57:59 +00004045 ( (VA_BITS8_DEFINED == vabits8 || VA_BITS8_UNDEFINED == vabits8)
njn1d0825f2006-03-27 11:37:07 +00004046 || (VA_BITS2_NOACCESS != extract_vabits2_from_vabits8(a, vabits8))
4047 )
4048 )
4049 )
4050 {
sewardjc1a2cda2005-04-21 17:34:00 +00004051 /* Handle common case quickly: a is mapped, the entire word32 it
4052 lives in is addressible. */
njn1d0825f2006-03-27 11:37:07 +00004053 // Convert full V-bits in register to compact 2-bit form.
njn4cf530b2006-04-06 13:33:48 +00004054 if (V_BITS8_DEFINED == vbits8) {
njndbf7ca72006-03-31 11:57:59 +00004055 insert_vabits2_into_vabits8( a, VA_BITS2_DEFINED,
njn1d0825f2006-03-27 11:37:07 +00004056 &(sm->vabits8[sm_off]) );
njn4cf530b2006-04-06 13:33:48 +00004057 } else if (V_BITS8_UNDEFINED == vbits8) {
njndbf7ca72006-03-31 11:57:59 +00004058 insert_vabits2_into_vabits8( a, VA_BITS2_UNDEFINED,
njn1d0825f2006-03-27 11:37:07 +00004059 &(sm->vabits8[sm_off]) );
4060 } else {
4061 /* Slow but general case -- writing partially defined bytes. */
4062 PROF_EVENT(272, "mc_STOREV8-slow2");
njn4cf530b2006-04-06 13:33:48 +00004063 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
njn1d0825f2006-03-27 11:37:07 +00004064 }
sewardjc1a2cda2005-04-21 17:34:00 +00004065 } else {
njn1d0825f2006-03-27 11:37:07 +00004066 /* Slow but general case. */
4067 PROF_EVENT(273, "mc_STOREV8-slow3");
njn4cf530b2006-04-06 13:33:48 +00004068 mc_STOREVn_slow( a, 8, (ULong)vbits8, False/*irrelevant*/ );
sewardjc1a2cda2005-04-21 17:34:00 +00004069 }
njn1d0825f2006-03-27 11:37:07 +00004070#endif
njn25e49d8e72002-09-23 09:36:25 +00004071}
4072
4073
sewardjc859fbf2005-04-22 21:10:28 +00004074/*------------------------------------------------------------*/
4075/*--- Functions called directly from generated code: ---*/
4076/*--- Value-check failure handlers. ---*/
4077/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004078
sewardj7cf4e6b2008-05-01 20:24:26 +00004079/* Call these ones when an origin is available ... */
4080VG_REGPARM(1)
4081void MC_(helperc_value_check0_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004082 MC_(record_cond_error) ( VG_(get_running_tid)(), (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004083}
4084
sewardj7cf4e6b2008-05-01 20:24:26 +00004085VG_REGPARM(1)
4086void MC_(helperc_value_check1_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004087 MC_(record_value_error) ( VG_(get_running_tid)(), 1, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004088}
4089
sewardj7cf4e6b2008-05-01 20:24:26 +00004090VG_REGPARM(1)
4091void MC_(helperc_value_check4_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004092 MC_(record_value_error) ( VG_(get_running_tid)(), 4, (UInt)origin );
njn25e49d8e72002-09-23 09:36:25 +00004093}
4094
sewardj7cf4e6b2008-05-01 20:24:26 +00004095VG_REGPARM(1)
4096void MC_(helperc_value_check8_fail_w_o) ( UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004097 MC_(record_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin );
sewardj11bcc4e2005-04-23 22:38:38 +00004098}
4099
sewardj7cf4e6b2008-05-01 20:24:26 +00004100VG_REGPARM(2)
4101void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) {
sewardj7ce71662008-05-02 10:33:15 +00004102 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin );
sewardj7cf4e6b2008-05-01 20:24:26 +00004103}
4104
4105/* ... and these when an origin isn't available. */
4106
4107VG_REGPARM(0)
4108void MC_(helperc_value_check0_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004109 MC_(record_cond_error) ( VG_(get_running_tid)(), 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004110}
4111
4112VG_REGPARM(0)
4113void MC_(helperc_value_check1_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004114 MC_(record_value_error) ( VG_(get_running_tid)(), 1, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004115}
4116
4117VG_REGPARM(0)
4118void MC_(helperc_value_check4_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004119 MC_(record_value_error) ( VG_(get_running_tid)(), 4, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004120}
4121
4122VG_REGPARM(0)
4123void MC_(helperc_value_check8_fail_no_o) ( void ) {
sewardj7ce71662008-05-02 10:33:15 +00004124 MC_(record_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ );
sewardj7cf4e6b2008-05-01 20:24:26 +00004125}
4126
4127VG_REGPARM(1)
4128void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) {
sewardj7ce71662008-05-02 10:33:15 +00004129 MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ );
sewardj95448072004-11-22 20:19:51 +00004130}
4131
njn25e49d8e72002-09-23 09:36:25 +00004132
sewardjc2c12c22006-03-08 13:20:09 +00004133/*------------------------------------------------------------*/
4134/*--- Metadata get/set functions, for client requests. ---*/
4135/*------------------------------------------------------------*/
4136
njn1d0825f2006-03-27 11:37:07 +00004137// Nb: this expands the V+A bits out into register-form V bits, even though
4138// they're in memory. This is for backward compatibility, and because it's
4139// probably what the user wants.
4140
4141/* Copy Vbits from/to address 'a'. Returns: 1 == OK, 2 == alignment
sewardjc2c12c22006-03-08 13:20:09 +00004142 error [no longer used], 3 == addressing error. */
njn718d3b12006-12-16 00:54:12 +00004143/* Nb: We used to issue various definedness/addressability errors from here,
4144 but we took them out because they ranged from not-very-helpful to
4145 downright annoying, and they complicated the error data structures. */
sewardjc2c12c22006-03-08 13:20:09 +00004146static Int mc_get_or_set_vbits_for_client (
4147 ThreadId tid,
njn1d0825f2006-03-27 11:37:07 +00004148 Addr a,
4149 Addr vbits,
4150 SizeT szB,
sewardjc2c12c22006-03-08 13:20:09 +00004151 Bool setting /* True <=> set vbits, False <=> get vbits */
4152)
4153{
sewardjc2c12c22006-03-08 13:20:09 +00004154 SizeT i;
njn1d0825f2006-03-27 11:37:07 +00004155 Bool ok;
4156 UChar vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004157
njn1d0825f2006-03-27 11:37:07 +00004158 /* Check that arrays are addressible before doing any getting/setting. */
4159 for (i = 0; i < szB; i++) {
njn718d3b12006-12-16 00:54:12 +00004160 if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
4161 VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
njn1d0825f2006-03-27 11:37:07 +00004162 return 3;
sewardjc2c12c22006-03-08 13:20:09 +00004163 }
4164 }
njn1d0825f2006-03-27 11:37:07 +00004165
sewardjc2c12c22006-03-08 13:20:09 +00004166 /* Do the copy */
4167 if (setting) {
njn1d0825f2006-03-27 11:37:07 +00004168 /* setting */
4169 for (i = 0; i < szB; i++) {
4170 ok = set_vbits8(a + i, ((UChar*)vbits)[i]);
4171 tl_assert(ok);
sewardjc2c12c22006-03-08 13:20:09 +00004172 }
4173 } else {
4174 /* getting */
njn1d0825f2006-03-27 11:37:07 +00004175 for (i = 0; i < szB; i++) {
4176 ok = get_vbits8(a + i, &vbits8);
4177 tl_assert(ok);
njn1d0825f2006-03-27 11:37:07 +00004178 ((UChar*)vbits)[i] = vbits8;
sewardjc2c12c22006-03-08 13:20:09 +00004179 }
4180 // The bytes in vbits[] have now been set, so mark them as such.
njndbf7ca72006-03-31 11:57:59 +00004181 MC_(make_mem_defined)(vbits, szB);
njn1d0825f2006-03-27 11:37:07 +00004182 }
sewardjc2c12c22006-03-08 13:20:09 +00004183
4184 return 1;
4185}
sewardj05fe85e2005-04-27 22:46:36 +00004186
4187
4188/*------------------------------------------------------------*/
4189/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
4190/*------------------------------------------------------------*/
4191
4192/* For the memory leak detector, say whether an entire 64k chunk of
4193 address space is possibly in use, or not. If in doubt return
4194 True.
4195*/
4196static
4197Bool mc_is_within_valid_secondary ( Addr a )
4198{
4199 SecMap* sm = maybe_get_secmap_for ( a );
sewardj05a46732006-10-17 01:28:10 +00004200 if (sm == NULL || sm == &sm_distinguished[SM_DIST_NOACCESS]
sewardj7ce71662008-05-02 10:33:15 +00004201 || MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004202 /* Definitely not in use. */
4203 return False;
4204 } else {
4205 return True;
4206 }
4207}
4208
4209
4210/* For the memory leak detector, say whether or not a given word
4211 address is to be regarded as valid. */
4212static
4213Bool mc_is_valid_aligned_word ( Addr a )
4214{
4215 tl_assert(sizeof(UWord) == 4 || sizeof(UWord) == 8);
4216 if (sizeof(UWord) == 4) {
4217 tl_assert(VG_IS_4_ALIGNED(a));
4218 } else {
4219 tl_assert(VG_IS_8_ALIGNED(a));
4220 }
sewardj7cf4e6b2008-05-01 20:24:26 +00004221 if (is_mem_defined( a, sizeof(UWord), NULL, NULL) == MC_Ok
sewardj7ce71662008-05-02 10:33:15 +00004222 && !MC_(in_ignored_range)(a)) {
sewardj05fe85e2005-04-27 22:46:36 +00004223 return True;
4224 } else {
4225 return False;
4226 }
4227}
sewardja4495682002-10-21 07:29:59 +00004228
4229
nethercote996901a2004-08-03 13:29:09 +00004230/* Leak detector for this tool. We don't actually do anything, merely
sewardja4495682002-10-21 07:29:59 +00004231 run the generic leak detector with suitable parameters for this
nethercote996901a2004-08-03 13:29:09 +00004232 tool. */
njnb8dca862005-03-14 02:42:44 +00004233static void mc_detect_memory_leaks ( ThreadId tid, LeakCheckMode mode )
njn25e49d8e72002-09-23 09:36:25 +00004234{
njn1d0825f2006-03-27 11:37:07 +00004235 MC_(do_detect_memory_leaks) (
sewardj05fe85e2005-04-27 22:46:36 +00004236 tid,
4237 mode,
4238 mc_is_within_valid_secondary,
4239 mc_is_valid_aligned_word
4240 );
njn25e49d8e72002-09-23 09:36:25 +00004241}
4242
4243
sewardjc859fbf2005-04-22 21:10:28 +00004244/*------------------------------------------------------------*/
4245/*--- Initialisation ---*/
4246/*------------------------------------------------------------*/
4247
4248static void init_shadow_memory ( void )
4249{
4250 Int i;
4251 SecMap* sm;
4252
njn1d0825f2006-03-27 11:37:07 +00004253 tl_assert(V_BIT_UNDEFINED == 1);
4254 tl_assert(V_BIT_DEFINED == 0);
4255 tl_assert(V_BITS8_UNDEFINED == 0xFF);
4256 tl_assert(V_BITS8_DEFINED == 0);
4257
sewardjc859fbf2005-04-22 21:10:28 +00004258 /* Build the 3 distinguished secondaries */
sewardjc859fbf2005-04-22 21:10:28 +00004259 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004260 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_NOACCESS;
sewardjc859fbf2005-04-22 21:10:28 +00004261
njndbf7ca72006-03-31 11:57:59 +00004262 sm = &sm_distinguished[SM_DIST_UNDEFINED];
4263 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_UNDEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004264
njndbf7ca72006-03-31 11:57:59 +00004265 sm = &sm_distinguished[SM_DIST_DEFINED];
4266 for (i = 0; i < SM_CHUNKS; i++) sm->vabits8[i] = VA_BITS8_DEFINED;
sewardjc859fbf2005-04-22 21:10:28 +00004267
4268 /* Set up the primary map. */
4269 /* These entries gradually get overwritten as the used address
4270 space expands. */
4271 for (i = 0; i < N_PRIMARY_MAP; i++)
4272 primary_map[i] = &sm_distinguished[SM_DIST_NOACCESS];
4273
sewardj05a46732006-10-17 01:28:10 +00004274 /* Auxiliary primary maps */
4275 init_auxmap_L1_L2();
4276
sewardjc859fbf2005-04-22 21:10:28 +00004277 /* auxmap_size = auxmap_used = 0;
4278 no ... these are statically initialised */
njn1d0825f2006-03-27 11:37:07 +00004279
4280 /* Secondary V bit table */
4281 secVBitTable = createSecVBitTable();
sewardjc859fbf2005-04-22 21:10:28 +00004282}
4283
4284
4285/*------------------------------------------------------------*/
4286/*--- Sanity check machinery (permanently engaged) ---*/
4287/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00004288
njn51d827b2005-05-09 01:02:08 +00004289static Bool mc_cheap_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004290{
sewardj23eb2fd2005-04-22 16:29:19 +00004291 n_sanity_cheap++;
sewardjc1a2cda2005-04-21 17:34:00 +00004292 PROF_EVENT(490, "cheap_sanity_check");
sewardj7cf4e6b2008-05-01 20:24:26 +00004293 /* Check for sane operating level */
4294 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4295 return False;
4296 /* nothing else useful we can rapidly check */
jseward9800fd32004-01-04 23:08:04 +00004297 return True;
njn25e49d8e72002-09-23 09:36:25 +00004298}
4299
njn51d827b2005-05-09 01:02:08 +00004300static Bool mc_expensive_sanity_check ( void )
njn25e49d8e72002-09-23 09:36:25 +00004301{
sewardj05a46732006-10-17 01:28:10 +00004302 Int i;
4303 Word n_secmaps_found;
sewardj45d94cc2005-04-20 14:44:11 +00004304 SecMap* sm;
sewardj05a46732006-10-17 01:28:10 +00004305 HChar* errmsg;
sewardj23eb2fd2005-04-22 16:29:19 +00004306 Bool bad = False;
njn25e49d8e72002-09-23 09:36:25 +00004307
sewardj05a46732006-10-17 01:28:10 +00004308 if (0) VG_(printf)("expensive sanity check\n");
4309 if (0) return True;
4310
sewardj23eb2fd2005-04-22 16:29:19 +00004311 n_sanity_expensive++;
sewardjc1a2cda2005-04-21 17:34:00 +00004312 PROF_EVENT(491, "expensive_sanity_check");
4313
sewardj7cf4e6b2008-05-01 20:24:26 +00004314 /* Check for sane operating level */
4315 if (MC_(clo_mc_level) < 1 || MC_(clo_mc_level) > 3)
4316 return False;
4317
njn1d0825f2006-03-27 11:37:07 +00004318 /* Check that the 3 distinguished SMs are still as they should be. */
njn25e49d8e72002-09-23 09:36:25 +00004319
njndbf7ca72006-03-31 11:57:59 +00004320 /* Check noaccess DSM. */
sewardj45d94cc2005-04-20 14:44:11 +00004321 sm = &sm_distinguished[SM_DIST_NOACCESS];
njn1d0825f2006-03-27 11:37:07 +00004322 for (i = 0; i < SM_CHUNKS; i++)
4323 if (sm->vabits8[i] != VA_BITS8_NOACCESS)
sewardj23eb2fd2005-04-22 16:29:19 +00004324 bad = True;
njn25e49d8e72002-09-23 09:36:25 +00004325
njndbf7ca72006-03-31 11:57:59 +00004326 /* Check undefined DSM. */
4327 sm = &sm_distinguished[SM_DIST_UNDEFINED];
njn1d0825f2006-03-27 11:37:07 +00004328 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004329 if (sm->vabits8[i] != VA_BITS8_UNDEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004330 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004331
njndbf7ca72006-03-31 11:57:59 +00004332 /* Check defined DSM. */
4333 sm = &sm_distinguished[SM_DIST_DEFINED];
njn1d0825f2006-03-27 11:37:07 +00004334 for (i = 0; i < SM_CHUNKS; i++)
njndbf7ca72006-03-31 11:57:59 +00004335 if (sm->vabits8[i] != VA_BITS8_DEFINED)
sewardj23eb2fd2005-04-22 16:29:19 +00004336 bad = True;
sewardj45d94cc2005-04-20 14:44:11 +00004337
sewardj23eb2fd2005-04-22 16:29:19 +00004338 if (bad) {
4339 VG_(printf)("memcheck expensive sanity: "
4340 "distinguished_secondaries have changed\n");
4341 return False;
4342 }
4343
njn1d0825f2006-03-27 11:37:07 +00004344 /* If we're not checking for undefined value errors, the secondary V bit
4345 * table should be empty. */
sewardj7cf4e6b2008-05-01 20:24:26 +00004346 if (MC_(clo_mc_level) == 1) {
njne2a9ad32007-09-17 05:30:48 +00004347 if (0 != VG_(OSetGen_Size)(secVBitTable))
njn1d0825f2006-03-27 11:37:07 +00004348 return False;
4349 }
4350
sewardj05a46732006-10-17 01:28:10 +00004351 /* check the auxiliary maps, very thoroughly */
4352 n_secmaps_found = 0;
4353 errmsg = check_auxmap_L1_L2_sanity( &n_secmaps_found );
4354 if (errmsg) {
4355 VG_(printf)("memcheck expensive sanity, auxmaps:\n\t%s", errmsg);
sewardj23eb2fd2005-04-22 16:29:19 +00004356 return False;
4357 }
4358
sewardj05a46732006-10-17 01:28:10 +00004359 /* n_secmaps_found is now the number referred to by the auxiliary
4360 primary map. Now add on the ones referred to by the main
4361 primary map. */
sewardj23eb2fd2005-04-22 16:29:19 +00004362 for (i = 0; i < N_PRIMARY_MAP; i++) {
sewardj05a46732006-10-17 01:28:10 +00004363 if (primary_map[i] == NULL) {
sewardj23eb2fd2005-04-22 16:29:19 +00004364 bad = True;
4365 } else {
sewardj05a46732006-10-17 01:28:10 +00004366 if (!is_distinguished_sm(primary_map[i]))
sewardj23eb2fd2005-04-22 16:29:19 +00004367 n_secmaps_found++;
4368 }
4369 }
4370
sewardj05a46732006-10-17 01:28:10 +00004371 /* check that the number of secmaps issued matches the number that
4372 are reachable (iow, no secmap leaks) */
njn1d0825f2006-03-27 11:37:07 +00004373 if (n_secmaps_found != (n_issued_SMs - n_deissued_SMs))
sewardj23eb2fd2005-04-22 16:29:19 +00004374 bad = True;
4375
4376 if (bad) {
4377 VG_(printf)("memcheck expensive sanity: "
4378 "apparent secmap leakage\n");
4379 return False;
4380 }
4381
sewardj23eb2fd2005-04-22 16:29:19 +00004382 if (bad) {
4383 VG_(printf)("memcheck expensive sanity: "
4384 "auxmap covers wrong address space\n");
4385 return False;
4386 }
4387
4388 /* there is only one pointer to each secmap (expensive) */
njn25e49d8e72002-09-23 09:36:25 +00004389
4390 return True;
4391}
sewardj45d94cc2005-04-20 14:44:11 +00004392
njn25e49d8e72002-09-23 09:36:25 +00004393/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00004394/*--- Command line args ---*/
njn25e49d8e72002-09-23 09:36:25 +00004395/*------------------------------------------------------------*/
4396
njn1d0825f2006-03-27 11:37:07 +00004397Bool MC_(clo_partial_loads_ok) = False;
sewardjfa4ca3b2007-11-30 17:19:36 +00004398Long MC_(clo_freelist_vol) = 10*1000*1000LL;
njn1d0825f2006-03-27 11:37:07 +00004399LeakCheckMode MC_(clo_leak_check) = LC_Summary;
4400VgRes MC_(clo_leak_resolution) = Vg_LowRes;
4401Bool MC_(clo_show_reachable) = False;
4402Bool MC_(clo_workaround_gcc296_bugs) = False;
sewardjeb0fa932007-11-30 21:41:40 +00004403Int MC_(clo_malloc_fill) = -1;
4404Int MC_(clo_free_fill) = -1;
sewardj7cf4e6b2008-05-01 20:24:26 +00004405Int MC_(clo_mc_level) = 2;
njn1d0825f2006-03-27 11:37:07 +00004406
4407static Bool mc_process_cmd_line_options(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00004408{
sewardj7cf4e6b2008-05-01 20:24:26 +00004409 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
4410
4411 /* Set MC_(clo_mc_level):
4412 1 = A bit tracking only
4413 2 = A and V bit tracking, but no V bit origins
4414 3 = A and V bit tracking, and V bit origins
4415
4416 Do this by inspecting --undef-value-errors= and
4417 --track-origins=. Reject the case --undef-value-errors=no
4418 --track-origins=yes as meaningless.
4419 */
4420 if (0 == VG_(strcmp)(arg, "--undef-value-errors=no")) {
4421 if (MC_(clo_mc_level) == 3)
4422 goto mc_level_error;
4423 MC_(clo_mc_level) = 1;
4424 return True;
4425 }
4426 if (0 == VG_(strcmp)(arg, "--undef-value-errors=yes")) {
4427 if (MC_(clo_mc_level) == 1)
4428 MC_(clo_mc_level) = 2;
4429 return True;
4430 }
4431 if (0 == VG_(strcmp)(arg, "--track-origins=no")) {
4432 if (MC_(clo_mc_level) == 3)
4433 MC_(clo_mc_level) = 2;
4434 return True;
4435 }
4436 if (0 == VG_(strcmp)(arg, "--track-origins=yes")) {
4437 if (MC_(clo_mc_level) == 1)
4438 goto mc_level_error;
4439 MC_(clo_mc_level) = 3;
4440 return True;
4441 }
4442
njn1d0825f2006-03-27 11:37:07 +00004443 VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok))
4444 else VG_BOOL_CLO(arg, "--show-reachable", MC_(clo_show_reachable))
4445 else VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",MC_(clo_workaround_gcc296_bugs))
4446
sewardjfa4ca3b2007-11-30 17:19:36 +00004447 else VG_BNUM_CLO(arg, "--freelist-vol", MC_(clo_freelist_vol),
4448 0, 10*1000*1000*1000LL)
njn1d0825f2006-03-27 11:37:07 +00004449
4450 else if (VG_CLO_STREQ(arg, "--leak-check=no"))
4451 MC_(clo_leak_check) = LC_Off;
4452 else if (VG_CLO_STREQ(arg, "--leak-check=summary"))
4453 MC_(clo_leak_check) = LC_Summary;
4454 else if (VG_CLO_STREQ(arg, "--leak-check=yes") ||
4455 VG_CLO_STREQ(arg, "--leak-check=full"))
4456 MC_(clo_leak_check) = LC_Full;
4457
4458 else if (VG_CLO_STREQ(arg, "--leak-resolution=low"))
4459 MC_(clo_leak_resolution) = Vg_LowRes;
4460 else if (VG_CLO_STREQ(arg, "--leak-resolution=med"))
4461 MC_(clo_leak_resolution) = Vg_MedRes;
4462 else if (VG_CLO_STREQ(arg, "--leak-resolution=high"))
4463 MC_(clo_leak_resolution) = Vg_HighRes;
4464
sewardj05a46732006-10-17 01:28:10 +00004465 else if (VG_CLO_STREQN(16,arg,"--ignore-ranges=")) {
4466 Int i;
4467 UChar* txt = (UChar*)(arg+16);
4468 Bool ok = parse_ignore_ranges(txt);
4469 if (!ok)
4470 return False;
4471 tl_assert(ignoreRanges.used >= 0);
4472 tl_assert(ignoreRanges.used < M_IGNORE_RANGES);
4473 for (i = 0; i < ignoreRanges.used; i++) {
4474 Addr s = ignoreRanges.start[i];
4475 Addr e = ignoreRanges.end[i];
4476 Addr limit = 0x4000000; /* 64M - entirely arbitrary limit */
4477 if (e <= s) {
4478 VG_(message)(Vg_DebugMsg,
4479 "ERROR: --ignore-ranges: end <= start in range:");
4480 VG_(message)(Vg_DebugMsg,
4481 " 0x%lx-0x%lx", s, e);
4482 return False;
4483 }
4484 if (e - s > limit) {
4485 VG_(message)(Vg_DebugMsg,
4486 "ERROR: --ignore-ranges: suspiciously large range:");
4487 VG_(message)(Vg_DebugMsg,
4488 " 0x%lx-0x%lx (size %ld)", s, e, (UWord)(e-s));
4489 return False;
4490 }
4491 }
4492 }
4493
sewardjeb0fa932007-11-30 21:41:40 +00004494 else VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00, 0xFF)
4495 else VG_BHEX_CLO(arg, "--free-fill", MC_(clo_free_fill), 0x00, 0xFF)
4496
njn1d0825f2006-03-27 11:37:07 +00004497 else
4498 return VG_(replacement_malloc_process_cmd_line_option)(arg);
4499
4500 return True;
sewardj7cf4e6b2008-05-01 20:24:26 +00004501 /*NOTREACHED*/
4502
4503 mc_level_error:
4504 VG_(message)(Vg_DebugMsg, "ERROR: --track-origins=yes has no effect "
4505 "when --undef-value-errors=no");
4506 return False;
njn25e49d8e72002-09-23 09:36:25 +00004507}
4508
njn51d827b2005-05-09 01:02:08 +00004509static void mc_print_usage(void)
njn25e49d8e72002-09-23 09:36:25 +00004510{
njn1d0825f2006-03-27 11:37:07 +00004511 VG_(printf)(
4512" --leak-check=no|summary|full search for memory leaks at exit? [summary]\n"
4513" --leak-resolution=low|med|high how much bt merging in leak check [low]\n"
4514" --show-reachable=no|yes show reachable blocks in leak check? [no]\n"
4515" --undef-value-errors=no|yes check for undefined value errors [yes]\n"
sewardj7cf4e6b2008-05-01 20:24:26 +00004516" --track-origins=no|yes show origins of undefined values? [no]\n"
njn1d0825f2006-03-27 11:37:07 +00004517" --partial-loads-ok=no|yes too hard to explain here; see manual [no]\n"
sewardjfa4ca3b2007-11-30 17:19:36 +00004518" --freelist-vol=<number> volume of freed blocks queue [10000000]\n"
njn1d0825f2006-03-27 11:37:07 +00004519" --workaround-gcc296-bugs=no|yes self explanatory [no]\n"
sewardj05a46732006-10-17 01:28:10 +00004520" --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS] assume given addresses are OK\n"
sewardjeb0fa932007-11-30 21:41:40 +00004521" --malloc-fill=<hexnumber> fill malloc'd areas with given value\n"
4522" --free-fill=<hexnumber> fill free'd areas with given value\n"
njn1d0825f2006-03-27 11:37:07 +00004523 );
4524 VG_(replacement_malloc_print_usage)();
njn3e884182003-04-15 13:03:23 +00004525}
4526
njn51d827b2005-05-09 01:02:08 +00004527static void mc_print_debug_usage(void)
njn3e884182003-04-15 13:03:23 +00004528{
njn1d0825f2006-03-27 11:37:07 +00004529 VG_(replacement_malloc_print_debug_usage)();
njn25e49d8e72002-09-23 09:36:25 +00004530}
4531
sewardjf3418c02005-11-08 14:10:24 +00004532
nethercote8b76fe52004-11-08 19:20:09 +00004533/*------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00004534/*--- Client blocks ---*/
nethercote8b76fe52004-11-08 19:20:09 +00004535/*------------------------------------------------------------*/
4536
4537/* Client block management:
4538
4539 This is managed as an expanding array of client block descriptors.
4540 Indices of live descriptors are issued to the client, so it can ask
4541 to free them later. Therefore we cannot slide live entries down
4542 over dead ones. Instead we must use free/inuse flags and scan for
4543 an empty slot at allocation time. This in turn means allocation is
4544 relatively expensive, so we hope this does not happen too often.
nethercote8b76fe52004-11-08 19:20:09 +00004545
sewardjedc75ab2005-03-15 23:30:32 +00004546 An unused block has start == size == 0
4547*/
nethercote8b76fe52004-11-08 19:20:09 +00004548
sewardj7ce71662008-05-02 10:33:15 +00004549/* type CGenBlock is defined in mc_include.h */
nethercote8b76fe52004-11-08 19:20:09 +00004550
4551/* This subsystem is self-initialising. */
sewardj56adc352008-05-02 11:25:17 +00004552static UWord cgb_size = 0;
4553static UWord cgb_used = 0;
njn695c16e2005-03-27 03:40:28 +00004554static CGenBlock* cgbs = NULL;
nethercote8b76fe52004-11-08 19:20:09 +00004555
4556/* Stats for this subsystem. */
sewardj56adc352008-05-02 11:25:17 +00004557static ULong cgb_used_MAX = 0; /* Max in use. */
4558static ULong cgb_allocs = 0; /* Number of allocs. */
4559static ULong cgb_discards = 0; /* Number of discards. */
4560static ULong cgb_search = 0; /* Number of searches. */
nethercote8b76fe52004-11-08 19:20:09 +00004561
4562
sewardj7ce71662008-05-02 10:33:15 +00004563/* Get access to the client block array. */
4564void MC_(get_ClientBlock_array)( /*OUT*/CGenBlock** blocks,
4565 /*OUT*/UWord* nBlocks )
4566{
4567 *blocks = cgbs;
4568 *nBlocks = cgb_used;
4569}
4570
4571
nethercote8b76fe52004-11-08 19:20:09 +00004572static
njn695c16e2005-03-27 03:40:28 +00004573Int alloc_client_block ( void )
nethercote8b76fe52004-11-08 19:20:09 +00004574{
sewardj56adc352008-05-02 11:25:17 +00004575 UWord i, sz_new;
nethercote8b76fe52004-11-08 19:20:09 +00004576 CGenBlock* cgbs_new;
4577
njn695c16e2005-03-27 03:40:28 +00004578 cgb_allocs++;
nethercote8b76fe52004-11-08 19:20:09 +00004579
njn695c16e2005-03-27 03:40:28 +00004580 for (i = 0; i < cgb_used; i++) {
4581 cgb_search++;
4582 if (cgbs[i].start == 0 && cgbs[i].size == 0)
nethercote8b76fe52004-11-08 19:20:09 +00004583 return i;
4584 }
4585
4586 /* Not found. Try to allocate one at the end. */
njn695c16e2005-03-27 03:40:28 +00004587 if (cgb_used < cgb_size) {
4588 cgb_used++;
4589 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004590 }
4591
4592 /* Ok, we have to allocate a new one. */
njn695c16e2005-03-27 03:40:28 +00004593 tl_assert(cgb_used == cgb_size);
4594 sz_new = (cgbs == NULL) ? 10 : (2 * cgb_size);
nethercote8b76fe52004-11-08 19:20:09 +00004595
4596 cgbs_new = VG_(malloc)( sz_new * sizeof(CGenBlock) );
njn695c16e2005-03-27 03:40:28 +00004597 for (i = 0; i < cgb_used; i++)
4598 cgbs_new[i] = cgbs[i];
nethercote8b76fe52004-11-08 19:20:09 +00004599
njn695c16e2005-03-27 03:40:28 +00004600 if (cgbs != NULL)
4601 VG_(free)( cgbs );
4602 cgbs = cgbs_new;
nethercote8b76fe52004-11-08 19:20:09 +00004603
njn695c16e2005-03-27 03:40:28 +00004604 cgb_size = sz_new;
4605 cgb_used++;
4606 if (cgb_used > cgb_used_MAX)
4607 cgb_used_MAX = cgb_used;
4608 return cgb_used-1;
nethercote8b76fe52004-11-08 19:20:09 +00004609}
4610
4611
4612static void show_client_block_stats ( void )
4613{
4614 VG_(message)(Vg_DebugMsg,
sewardj56adc352008-05-02 11:25:17 +00004615 "general CBs: %llu allocs, %llu discards, %llu maxinuse, %llu search",
njn695c16e2005-03-27 03:40:28 +00004616 cgb_allocs, cgb_discards, cgb_used_MAX, cgb_search
nethercote8b76fe52004-11-08 19:20:09 +00004617 );
4618}
4619
nethercote8b76fe52004-11-08 19:20:09 +00004620
sewardj7ce71662008-05-02 10:33:15 +00004621/*------------------------------------------------------------*/
4622/*--- Client requests ---*/
4623/*------------------------------------------------------------*/
nethercote8b76fe52004-11-08 19:20:09 +00004624
njn51d827b2005-05-09 01:02:08 +00004625static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
nethercote8b76fe52004-11-08 19:20:09 +00004626{
4627 Int i;
4628 Bool ok;
4629 Addr bad_addr;
4630
njnfc26ff92004-11-22 19:12:49 +00004631 if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
sewardj7ce71662008-05-02 10:33:15 +00004632 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
4633 && VG_USERREQ__FREELIKE_BLOCK != arg[0]
4634 && VG_USERREQ__CREATE_MEMPOOL != arg[0]
4635 && VG_USERREQ__DESTROY_MEMPOOL != arg[0]
4636 && VG_USERREQ__MEMPOOL_ALLOC != arg[0]
4637 && VG_USERREQ__MEMPOOL_FREE != arg[0]
4638 && VG_USERREQ__MEMPOOL_TRIM != arg[0]
4639 && VG_USERREQ__MOVE_MEMPOOL != arg[0]
4640 && VG_USERREQ__MEMPOOL_CHANGE != arg[0]
4641 && VG_USERREQ__MEMPOOL_EXISTS != arg[0])
nethercote8b76fe52004-11-08 19:20:09 +00004642 return False;
4643
4644 switch (arg[0]) {
njndbf7ca72006-03-31 11:57:59 +00004645 case VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE:
4646 ok = is_mem_addressable ( arg[1], arg[2], &bad_addr );
nethercote8b76fe52004-11-08 19:20:09 +00004647 if (!ok)
sewardj7ce71662008-05-02 10:33:15 +00004648 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004649 *ret = ok ? (UWord)NULL : bad_addr;
sewardj8cf88b72005-07-08 01:29:33 +00004650 break;
nethercote8b76fe52004-11-08 19:20:09 +00004651
njndbf7ca72006-03-31 11:57:59 +00004652 case VG_USERREQ__CHECK_MEM_IS_DEFINED: {
nethercote8b76fe52004-11-08 19:20:09 +00004653 MC_ReadResult res;
sewardj7cf4e6b2008-05-01 20:24:26 +00004654 UInt otag = 0;
4655 res = is_mem_defined ( arg[1], arg[2], &bad_addr, &otag );
nethercote8b76fe52004-11-08 19:20:09 +00004656 if (MC_AddrErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004657 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/True, 0 );
nethercote8b76fe52004-11-08 19:20:09 +00004658 else if (MC_ValueErr == res)
sewardj7ce71662008-05-02 10:33:15 +00004659 MC_(record_user_error) ( tid, bad_addr, /*isAddrErr*/False, otag );
nethercote8b76fe52004-11-08 19:20:09 +00004660 *ret = ( res==MC_Ok ? (UWord)NULL : bad_addr );
sewardj8cf88b72005-07-08 01:29:33 +00004661 break;
nethercote8b76fe52004-11-08 19:20:09 +00004662 }
4663
4664 case VG_USERREQ__DO_LEAK_CHECK:
njnb8dca862005-03-14 02:42:44 +00004665 mc_detect_memory_leaks(tid, arg[1] ? LC_Summary : LC_Full);
sewardj8cf88b72005-07-08 01:29:33 +00004666 *ret = 0; /* return value is meaningless */
4667 break;
nethercote8b76fe52004-11-08 19:20:09 +00004668
njndbf7ca72006-03-31 11:57:59 +00004669 case VG_USERREQ__MAKE_MEM_NOACCESS:
4670 MC_(make_mem_noaccess) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004671 *ret = -1;
4672 break;
nethercote8b76fe52004-11-08 19:20:09 +00004673
njndbf7ca72006-03-31 11:57:59 +00004674 case VG_USERREQ__MAKE_MEM_UNDEFINED:
sewardj7ce71662008-05-02 10:33:15 +00004675 make_mem_undefined_w_tid_and_okind ( arg[1], arg[2], tid,
4676 MC_OKIND_USER );
sewardjedc75ab2005-03-15 23:30:32 +00004677 *ret = -1;
sewardj8cf88b72005-07-08 01:29:33 +00004678 break;
nethercote8b76fe52004-11-08 19:20:09 +00004679
njndbf7ca72006-03-31 11:57:59 +00004680 case VG_USERREQ__MAKE_MEM_DEFINED:
4681 MC_(make_mem_defined) ( arg[1], arg[2] );
sewardj8cf88b72005-07-08 01:29:33 +00004682 *ret = -1;
nethercote8b76fe52004-11-08 19:20:09 +00004683 break;
4684
njndbf7ca72006-03-31 11:57:59 +00004685 case VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE:
4686 make_mem_defined_if_addressable ( arg[1], arg[2] );
sewardjfb1e9ad2006-03-10 13:41:58 +00004687 *ret = -1;
4688 break;
4689
sewardjedc75ab2005-03-15 23:30:32 +00004690 case VG_USERREQ__CREATE_BLOCK: /* describe a block */
sewardj8cf88b72005-07-08 01:29:33 +00004691 if (arg[1] != 0 && arg[2] != 0) {
4692 i = alloc_client_block();
4693 /* VG_(printf)("allocated %d %p\n", i, cgbs); */
4694 cgbs[i].start = arg[1];
4695 cgbs[i].size = arg[2];
4696 cgbs[i].desc = VG_(strdup)((Char *)arg[3]);
sewardj39f34232007-11-09 23:02:28 +00004697 cgbs[i].where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
sewardjedc75ab2005-03-15 23:30:32 +00004698
sewardj8cf88b72005-07-08 01:29:33 +00004699 *ret = i;
4700 } else
4701 *ret = -1;
4702 break;
sewardjedc75ab2005-03-15 23:30:32 +00004703
nethercote8b76fe52004-11-08 19:20:09 +00004704 case VG_USERREQ__DISCARD: /* discard */
njn695c16e2005-03-27 03:40:28 +00004705 if (cgbs == NULL
4706 || arg[2] >= cgb_used ||
sewardj8cf88b72005-07-08 01:29:33 +00004707 (cgbs[arg[2]].start == 0 && cgbs[arg[2]].size == 0)) {
sewardjedc75ab2005-03-15 23:30:32 +00004708 *ret = 1;
sewardj8cf88b72005-07-08 01:29:33 +00004709 } else {
4710 tl_assert(arg[2] >= 0 && arg[2] < cgb_used);
4711 cgbs[arg[2]].start = cgbs[arg[2]].size = 0;
4712 VG_(free)(cgbs[arg[2]].desc);
4713 cgb_discards++;
4714 *ret = 0;
4715 }
4716 break;
nethercote8b76fe52004-11-08 19:20:09 +00004717
sewardjc2c12c22006-03-08 13:20:09 +00004718 case VG_USERREQ__GET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004719 *ret = mc_get_or_set_vbits_for_client
4720 ( tid, arg[1], arg[2], arg[3], False /* get them */ );
4721 break;
4722
4723 case VG_USERREQ__SET_VBITS:
sewardjc2c12c22006-03-08 13:20:09 +00004724 *ret = mc_get_or_set_vbits_for_client
4725 ( tid, arg[1], arg[2], arg[3], True /* set them */ );
4726 break;
nethercote8b76fe52004-11-08 19:20:09 +00004727
njn1d0825f2006-03-27 11:37:07 +00004728 case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
4729 UWord** argp = (UWord**)arg;
4730 // MC_(bytes_leaked) et al were set by the last leak check (or zero
4731 // if no prior leak checks performed).
4732 *argp[1] = MC_(bytes_leaked) + MC_(bytes_indirect);
4733 *argp[2] = MC_(bytes_dubious);
4734 *argp[3] = MC_(bytes_reachable);
4735 *argp[4] = MC_(bytes_suppressed);
4736 // there is no argp[5]
4737 //*argp[5] = MC_(bytes_indirect);
njndbf7ca72006-03-31 11:57:59 +00004738 // XXX need to make *argp[1-4] defined
njn1d0825f2006-03-27 11:37:07 +00004739 *ret = 0;
4740 return True;
4741 }
4742 case VG_USERREQ__MALLOCLIKE_BLOCK: {
4743 Addr p = (Addr)arg[1];
4744 SizeT sizeB = arg[2];
4745 UInt rzB = arg[3];
4746 Bool is_zeroed = (Bool)arg[4];
4747
4748 MC_(new_block) ( tid, p, sizeB, /*ignored*/0, rzB, is_zeroed,
4749 MC_AllocCustom, MC_(malloc_list) );
4750 return True;
4751 }
4752 case VG_USERREQ__FREELIKE_BLOCK: {
4753 Addr p = (Addr)arg[1];
4754 UInt rzB = arg[2];
4755
4756 MC_(handle_free) ( tid, p, rzB, MC_AllocCustom );
4757 return True;
4758 }
4759
4760 case _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR: {
njn718d3b12006-12-16 00:54:12 +00004761 Char* s = (Char*)arg[1];
4762 Addr dst = (Addr) arg[2];
4763 Addr src = (Addr) arg[3];
4764 SizeT len = (SizeT)arg[4];
sewardj7ce71662008-05-02 10:33:15 +00004765 MC_(record_overlap_error)(tid, s, src, dst, len);
njn1d0825f2006-03-27 11:37:07 +00004766 return True;
4767 }
4768
4769 case VG_USERREQ__CREATE_MEMPOOL: {
4770 Addr pool = (Addr)arg[1];
4771 UInt rzB = arg[2];
4772 Bool is_zeroed = (Bool)arg[3];
4773
4774 MC_(create_mempool) ( pool, rzB, is_zeroed );
4775 return True;
4776 }
4777
4778 case VG_USERREQ__DESTROY_MEMPOOL: {
4779 Addr pool = (Addr)arg[1];
4780
4781 MC_(destroy_mempool) ( pool );
4782 return True;
4783 }
4784
4785 case VG_USERREQ__MEMPOOL_ALLOC: {
4786 Addr pool = (Addr)arg[1];
4787 Addr addr = (Addr)arg[2];
4788 UInt size = arg[3];
4789
4790 MC_(mempool_alloc) ( tid, pool, addr, size );
4791 return True;
4792 }
4793
4794 case VG_USERREQ__MEMPOOL_FREE: {
4795 Addr pool = (Addr)arg[1];
4796 Addr addr = (Addr)arg[2];
4797
4798 MC_(mempool_free) ( pool, addr );
4799 return True;
4800 }
4801
sewardj2c1c9df2006-07-28 00:06:37 +00004802 case VG_USERREQ__MEMPOOL_TRIM: {
4803 Addr pool = (Addr)arg[1];
4804 Addr addr = (Addr)arg[2];
4805 UInt size = arg[3];
4806
4807 MC_(mempool_trim) ( pool, addr, size );
4808 return True;
4809 }
4810
sewardjc740d762006-10-05 17:59:23 +00004811 case VG_USERREQ__MOVE_MEMPOOL: {
4812 Addr poolA = (Addr)arg[1];
4813 Addr poolB = (Addr)arg[2];
4814
4815 MC_(move_mempool) ( poolA, poolB );
4816 return True;
4817 }
4818
4819 case VG_USERREQ__MEMPOOL_CHANGE: {
4820 Addr pool = (Addr)arg[1];
4821 Addr addrA = (Addr)arg[2];
4822 Addr addrB = (Addr)arg[3];
4823 UInt size = arg[4];
4824
4825 MC_(mempool_change) ( pool, addrA, addrB, size );
4826 return True;
4827 }
4828
4829 case VG_USERREQ__MEMPOOL_EXISTS: {
4830 Addr pool = (Addr)arg[1];
4831
4832 *ret = (UWord) MC_(mempool_exists) ( pool );
4833 return True;
4834 }
4835
4836
nethercote8b76fe52004-11-08 19:20:09 +00004837 default:
njn1d0825f2006-03-27 11:37:07 +00004838 VG_(message)(Vg_UserMsg,
4839 "Warning: unknown memcheck client request code %llx",
4840 (ULong)arg[0]);
4841 return False;
nethercote8b76fe52004-11-08 19:20:09 +00004842 }
4843 return True;
4844}
njn25e49d8e72002-09-23 09:36:25 +00004845
4846/*------------------------------------------------------------*/
njn1d0825f2006-03-27 11:37:07 +00004847/*--- Crude profiling machinery. ---*/
4848/*------------------------------------------------------------*/
4849
4850// We track a number of interesting events (using PROF_EVENT)
4851// if MC_PROFILE_MEMORY is defined.
4852
4853#ifdef MC_PROFILE_MEMORY
4854
4855UInt MC_(event_ctr)[N_PROF_EVENTS];
4856HChar* MC_(event_ctr_name)[N_PROF_EVENTS];
4857
4858static void init_prof_mem ( void )
4859{
4860 Int i;
4861 for (i = 0; i < N_PROF_EVENTS; i++) {
4862 MC_(event_ctr)[i] = 0;
4863 MC_(event_ctr_name)[i] = NULL;
4864 }
4865}
4866
4867static void done_prof_mem ( void )
4868{
4869 Int i;
4870 Bool spaced = False;
4871 for (i = 0; i < N_PROF_EVENTS; i++) {
4872 if (!spaced && (i % 10) == 0) {
4873 VG_(printf)("\n");
4874 spaced = True;
4875 }
4876 if (MC_(event_ctr)[i] > 0) {
4877 spaced = False;
4878 VG_(printf)( "prof mem event %3d: %9d %s\n",
4879 i, MC_(event_ctr)[i],
4880 MC_(event_ctr_name)[i]
4881 ? MC_(event_ctr_name)[i] : "unnamed");
4882 }
4883 }
4884}
4885
4886#else
4887
4888static void init_prof_mem ( void ) { }
4889static void done_prof_mem ( void ) { }
4890
4891#endif
4892
sewardj7cf4e6b2008-05-01 20:24:26 +00004893
4894/*------------------------------------------------------------*/
4895/*--- Origin tracking stuff ---*/
4896/*------------------------------------------------------------*/
4897
4898/*--------------------------------------------*/
4899/*--- Origin tracking: load handlers ---*/
4900/*--------------------------------------------*/
4901
4902static INLINE UInt merge_origins ( UInt or1, UInt or2 ) {
4903 return or1 > or2 ? or1 : or2;
4904}
4905
4906UWord VG_REGPARM(1) MC_(helperc_b_load1)( Addr a ) {
4907 OCacheLine* line;
4908 UChar descr;
4909 UWord lineoff = oc_line_offset(a);
4910 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
4911
4912 if (OC_ENABLE_ASSERTIONS) {
4913 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
4914 }
4915
4916 line = find_OCacheLine( a );
4917
4918 descr = line->descr[lineoff];
4919 if (OC_ENABLE_ASSERTIONS) {
4920 tl_assert(descr < 0x10);
4921 }
4922
4923 if (LIKELY(0 == (descr & (1 << byteoff)))) {
4924 return 0;
4925 } else {
4926 return line->w32[lineoff];
4927 }
4928}
4929
4930UWord VG_REGPARM(1) MC_(helperc_b_load2)( Addr a ) {
4931 OCacheLine* line;
4932 UChar descr;
4933 UWord lineoff, byteoff;
4934
4935 if (UNLIKELY(a & 1)) {
4936 /* Handle misaligned case, slowly. */
4937 UInt oLo = (UInt)MC_(helperc_b_load1)( a + 0 );
4938 UInt oHi = (UInt)MC_(helperc_b_load1)( a + 1 );
4939 return merge_origins(oLo, oHi);
4940 }
4941
4942 lineoff = oc_line_offset(a);
4943 byteoff = a & 3; /* 0 or 2 */
4944
4945 if (OC_ENABLE_ASSERTIONS) {
4946 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
4947 }
4948 line = find_OCacheLine( a );
4949
4950 descr = line->descr[lineoff];
4951 if (OC_ENABLE_ASSERTIONS) {
4952 tl_assert(descr < 0x10);
4953 }
4954
4955 if (LIKELY(0 == (descr & (3 << byteoff)))) {
4956 return 0;
4957 } else {
4958 return line->w32[lineoff];
4959 }
4960}
4961
4962UWord VG_REGPARM(1) MC_(helperc_b_load4)( Addr a ) {
4963 OCacheLine* line;
4964 UChar descr;
4965 UWord lineoff;
4966
4967 if (UNLIKELY(a & 3)) {
4968 /* Handle misaligned case, slowly. */
4969 UInt oLo = (UInt)MC_(helperc_b_load2)( a + 0 );
4970 UInt oHi = (UInt)MC_(helperc_b_load2)( a + 2 );
4971 return merge_origins(oLo, oHi);
4972 }
4973
4974 lineoff = oc_line_offset(a);
4975 if (OC_ENABLE_ASSERTIONS) {
4976 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
4977 }
4978
4979 line = find_OCacheLine( a );
4980
4981 descr = line->descr[lineoff];
4982 if (OC_ENABLE_ASSERTIONS) {
4983 tl_assert(descr < 0x10);
4984 }
4985
4986 if (LIKELY(0 == descr)) {
4987 return 0;
4988 } else {
4989 return line->w32[lineoff];
4990 }
4991}
4992
4993UWord VG_REGPARM(1) MC_(helperc_b_load8)( Addr a ) {
4994 OCacheLine* line;
4995 UChar descrLo, descrHi, descr;
4996 UWord lineoff;
4997
4998 if (UNLIKELY(a & 7)) {
4999 /* Handle misaligned case, slowly. */
5000 UInt oLo = (UInt)MC_(helperc_b_load4)( a + 0 );
5001 UInt oHi = (UInt)MC_(helperc_b_load4)( a + 4 );
5002 return merge_origins(oLo, oHi);
5003 }
5004
5005 lineoff = oc_line_offset(a);
5006 if (OC_ENABLE_ASSERTIONS) {
5007 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5008 }
5009
5010 line = find_OCacheLine( a );
5011
5012 descrLo = line->descr[lineoff + 0];
5013 descrHi = line->descr[lineoff + 1];
5014 descr = descrLo | descrHi;
5015 if (OC_ENABLE_ASSERTIONS) {
5016 tl_assert(descr < 0x10);
5017 }
5018
5019 if (LIKELY(0 == descr)) {
5020 return 0; /* both 32-bit chunks are defined */
5021 } else {
5022 UInt oLo = descrLo == 0 ? 0 : line->w32[lineoff + 0];
5023 UInt oHi = descrHi == 0 ? 0 : line->w32[lineoff + 1];
5024 return merge_origins(oLo, oHi);
5025 }
5026}
5027
5028UWord VG_REGPARM(1) MC_(helperc_b_load16)( Addr a ) {
5029 UInt oLo = (UInt)MC_(helperc_b_load8)( a + 0 );
5030 UInt oHi = (UInt)MC_(helperc_b_load8)( a + 8 );
5031 UInt oBoth = merge_origins(oLo, oHi);
5032 return (UWord)oBoth;
5033}
5034
5035
5036/*--------------------------------------------*/
5037/*--- Origin tracking: store handlers ---*/
5038/*--------------------------------------------*/
5039
5040void VG_REGPARM(2) MC_(helperc_b_store1)( Addr a, UWord d32 ) {
5041 OCacheLine* line;
5042 UWord lineoff = oc_line_offset(a);
5043 UWord byteoff = a & 3; /* 0, 1, 2 or 3 */
5044
5045 if (OC_ENABLE_ASSERTIONS) {
5046 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5047 }
5048
5049 line = find_OCacheLine( a );
5050
5051 if (d32 == 0) {
5052 line->descr[lineoff] &= ~(1 << byteoff);
5053 } else {
5054 line->descr[lineoff] |= (1 << byteoff);
5055 line->w32[lineoff] = d32;
5056 }
5057}
5058
5059void VG_REGPARM(2) MC_(helperc_b_store2)( Addr a, UWord d32 ) {
5060 OCacheLine* line;
5061 UWord lineoff, byteoff;
5062
5063 if (UNLIKELY(a & 1)) {
5064 /* Handle misaligned case, slowly. */
5065 MC_(helperc_b_store1)( a + 0, d32 );
5066 MC_(helperc_b_store1)( a + 1, d32 );
5067 return;
5068 }
5069
5070 lineoff = oc_line_offset(a);
5071 byteoff = a & 3; /* 0 or 2 */
5072
5073 if (OC_ENABLE_ASSERTIONS) {
5074 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5075 }
5076
5077 line = find_OCacheLine( a );
5078
5079 if (d32 == 0) {
5080 line->descr[lineoff] &= ~(3 << byteoff);
5081 } else {
5082 line->descr[lineoff] |= (3 << byteoff);
5083 line->w32[lineoff] = d32;
5084 }
5085}
5086
5087void VG_REGPARM(2) MC_(helperc_b_store4)( Addr a, UWord d32 ) {
5088 OCacheLine* line;
5089 UWord lineoff;
5090
5091 if (UNLIKELY(a & 3)) {
5092 /* Handle misaligned case, slowly. */
5093 MC_(helperc_b_store2)( a + 0, d32 );
5094 MC_(helperc_b_store2)( a + 2, d32 );
5095 return;
5096 }
5097
5098 lineoff = oc_line_offset(a);
5099 if (OC_ENABLE_ASSERTIONS) {
5100 tl_assert(lineoff >= 0 && lineoff < OC_W32S_PER_LINE);
5101 }
5102
5103 line = find_OCacheLine( a );
5104
5105 if (d32 == 0) {
5106 line->descr[lineoff] = 0;
5107 } else {
5108 line->descr[lineoff] = 0xF;
5109 line->w32[lineoff] = d32;
5110 }
5111}
5112
5113void VG_REGPARM(2) MC_(helperc_b_store8)( Addr a, UWord d32 ) {
5114 OCacheLine* line;
5115 UWord lineoff;
5116
5117 if (UNLIKELY(a & 7)) {
5118 /* Handle misaligned case, slowly. */
5119 MC_(helperc_b_store4)( a + 0, d32 );
5120 MC_(helperc_b_store4)( a + 4, d32 );
5121 return;
5122 }
5123
5124 lineoff = oc_line_offset(a);
5125 if (OC_ENABLE_ASSERTIONS) {
5126 tl_assert(lineoff == (lineoff & 6)); /*0,2,4,6*//*since 8-aligned*/
5127 }
5128
5129 line = find_OCacheLine( a );
5130
5131 if (d32 == 0) {
5132 line->descr[lineoff + 0] = 0;
5133 line->descr[lineoff + 1] = 0;
5134 } else {
5135 line->descr[lineoff + 0] = 0xF;
5136 line->descr[lineoff + 1] = 0xF;
5137 line->w32[lineoff + 0] = d32;
5138 line->w32[lineoff + 1] = d32;
5139 }
5140}
5141
5142void VG_REGPARM(2) MC_(helperc_b_store16)( Addr a, UWord d32 ) {
5143 MC_(helperc_b_store8)( a + 0, d32 );
5144 MC_(helperc_b_store8)( a + 8, d32 );
5145}
5146
5147
5148/*--------------------------------------------*/
5149/*--- Origin tracking: sarp handlers ---*/
5150/*--------------------------------------------*/
5151
5152__attribute__((noinline))
5153static void ocache_sarp_Set_Origins ( Addr a, UWord len, UInt otag ) {
5154 if ((a & 1) && len >= 1) {
5155 MC_(helperc_b_store1)( a, otag );
5156 a++;
5157 len--;
5158 }
5159 if ((a & 2) && len >= 2) {
5160 MC_(helperc_b_store2)( a, otag );
5161 a += 2;
5162 len -= 2;
5163 }
5164 if (len >= 4)
5165 tl_assert(0 == (a & 3));
5166 while (len >= 4) {
5167 MC_(helperc_b_store4)( a, otag );
5168 a += 4;
5169 len -= 4;
5170 }
5171 if (len >= 2) {
5172 MC_(helperc_b_store2)( a, otag );
5173 a += 2;
5174 len -= 2;
5175 }
5176 if (len >= 1) {
5177 MC_(helperc_b_store1)( a, otag );
5178 a++;
5179 len--;
5180 }
5181 tl_assert(len == 0);
5182}
5183
5184__attribute__((noinline))
5185static void ocache_sarp_Clear_Origins ( Addr a, UWord len ) {
5186 if ((a & 1) && len >= 1) {
5187 MC_(helperc_b_store1)( a, 0 );
5188 a++;
5189 len--;
5190 }
5191 if ((a & 2) && len >= 2) {
5192 MC_(helperc_b_store2)( a, 0 );
5193 a += 2;
5194 len -= 2;
5195 }
5196 if (len >= 4)
5197 tl_assert(0 == (a & 3));
5198 while (len >= 4) {
5199 MC_(helperc_b_store4)( a, 0 );
5200 a += 4;
5201 len -= 4;
5202 }
5203 if (len >= 2) {
5204 MC_(helperc_b_store2)( a, 0 );
5205 a += 2;
5206 len -= 2;
5207 }
5208 if (len >= 1) {
5209 MC_(helperc_b_store1)( a, 0 );
5210 a++;
5211 len--;
5212 }
5213 tl_assert(len == 0);
5214}
5215
5216
njn1d0825f2006-03-27 11:37:07 +00005217/*------------------------------------------------------------*/
njn51d827b2005-05-09 01:02:08 +00005218/*--- Setup and finalisation ---*/
njn25e49d8e72002-09-23 09:36:25 +00005219/*------------------------------------------------------------*/
5220
njn51d827b2005-05-09 01:02:08 +00005221static void mc_post_clo_init ( void )
njn5c004e42002-11-18 11:04:50 +00005222{
sewardj71bc3cb2005-05-19 00:25:45 +00005223 /* If we've been asked to emit XML, mash around various other
5224 options so as to constrain the output somewhat. */
5225 if (VG_(clo_xml)) {
5226 /* Extract as much info as possible from the leak checker. */
njn1d0825f2006-03-27 11:37:07 +00005227 /* MC_(clo_show_reachable) = True; */
5228 MC_(clo_leak_check) = LC_Full;
sewardj71bc3cb2005-05-19 00:25:45 +00005229 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005230
5231 tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
5232
5233 if (MC_(clo_mc_level) == 3) {
5234 /* We're doing origin tracking. */
5235# ifdef PERF_FAST_STACK
5236 VG_(track_new_mem_stack_4_w_ECU) ( mc_new_mem_stack_4_w_ECU );
5237 VG_(track_new_mem_stack_8_w_ECU) ( mc_new_mem_stack_8_w_ECU );
5238 VG_(track_new_mem_stack_12_w_ECU) ( mc_new_mem_stack_12_w_ECU );
5239 VG_(track_new_mem_stack_16_w_ECU) ( mc_new_mem_stack_16_w_ECU );
5240 VG_(track_new_mem_stack_32_w_ECU) ( mc_new_mem_stack_32_w_ECU );
5241 VG_(track_new_mem_stack_112_w_ECU) ( mc_new_mem_stack_112_w_ECU );
5242 VG_(track_new_mem_stack_128_w_ECU) ( mc_new_mem_stack_128_w_ECU );
5243 VG_(track_new_mem_stack_144_w_ECU) ( mc_new_mem_stack_144_w_ECU );
5244 VG_(track_new_mem_stack_160_w_ECU) ( mc_new_mem_stack_160_w_ECU );
5245# endif
5246 VG_(track_new_mem_stack_w_ECU) ( mc_new_mem_stack_w_ECU );
5247 } else {
5248 /* Not doing origin tracking */
5249# ifdef PERF_FAST_STACK
5250 VG_(track_new_mem_stack_4) ( mc_new_mem_stack_4 );
5251 VG_(track_new_mem_stack_8) ( mc_new_mem_stack_8 );
5252 VG_(track_new_mem_stack_12) ( mc_new_mem_stack_12 );
5253 VG_(track_new_mem_stack_16) ( mc_new_mem_stack_16 );
5254 VG_(track_new_mem_stack_32) ( mc_new_mem_stack_32 );
5255 VG_(track_new_mem_stack_112) ( mc_new_mem_stack_112 );
5256 VG_(track_new_mem_stack_128) ( mc_new_mem_stack_128 );
5257 VG_(track_new_mem_stack_144) ( mc_new_mem_stack_144 );
5258 VG_(track_new_mem_stack_160) ( mc_new_mem_stack_160 );
5259# endif
5260 VG_(track_new_mem_stack) ( mc_new_mem_stack );
5261 }
sewardj9d624d12008-05-02 13:35:29 +00005262
5263 /* This origin tracking cache is huge (~100M), so only initialise
5264 if we need it. */
5265 if (MC_(clo_mc_level) >= 3) {
5266 init_OCache();
5267 tl_assert(ocache != NULL);
5268 tl_assert(ocacheL2 != NULL);
5269 } else {
5270 tl_assert(ocache == NULL);
5271 tl_assert(ocacheL2 == NULL);
5272 }
njn5c004e42002-11-18 11:04:50 +00005273}
5274
njn1d0825f2006-03-27 11:37:07 +00005275static void print_SM_info(char* type, int n_SMs)
5276{
5277 VG_(message)(Vg_DebugMsg,
5278 " memcheck: SMs: %s = %d (%dk, %dM)",
5279 type,
5280 n_SMs,
5281 n_SMs * sizeof(SecMap) / 1024,
5282 n_SMs * sizeof(SecMap) / (1024 * 1024) );
5283}
5284
njn51d827b2005-05-09 01:02:08 +00005285static void mc_fini ( Int exitcode )
njn5c004e42002-11-18 11:04:50 +00005286{
njn1d0825f2006-03-27 11:37:07 +00005287 MC_(print_malloc_stats)();
sewardj23eb2fd2005-04-22 16:29:19 +00005288
njn1d0825f2006-03-27 11:37:07 +00005289 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5290 if (MC_(clo_leak_check) == LC_Off)
5291 VG_(message)(Vg_UserMsg,
5292 "For a detailed leak analysis, rerun with: --leak-check=yes");
5293
5294 VG_(message)(Vg_UserMsg,
5295 "For counts of detected errors, rerun with: -v");
5296 }
sewardj7cf4e6b2008-05-01 20:24:26 +00005297
5298
sewardj7ce71662008-05-02 10:33:15 +00005299 if (MC_(any_value_errors) && !VG_(clo_xml) && VG_(clo_verbosity) >= 1
sewardj7cf4e6b2008-05-01 20:24:26 +00005300 && MC_(clo_mc_level) == 2) {
5301 VG_(message)(Vg_UserMsg,
5302 "Use --track-origins=yes to see where "
5303 "uninitialised values come from");
5304 }
5305
njn1d0825f2006-03-27 11:37:07 +00005306 if (MC_(clo_leak_check) != LC_Off)
5307 mc_detect_memory_leaks(1/*bogus ThreadId*/, MC_(clo_leak_check));
5308
5309 done_prof_mem();
sewardjae986ca2005-10-12 12:53:20 +00005310
sewardj45d94cc2005-04-20 14:44:11 +00005311 if (VG_(clo_verbosity) > 1) {
njn1d0825f2006-03-27 11:37:07 +00005312 SizeT max_secVBit_szB, max_SMs_szB, max_shmem_szB;
5313
sewardj45d94cc2005-04-20 14:44:11 +00005314 VG_(message)(Vg_DebugMsg,
sewardj23eb2fd2005-04-22 16:29:19 +00005315 " memcheck: sanity checks: %d cheap, %d expensive",
5316 n_sanity_cheap, n_sanity_expensive );
sewardj45d94cc2005-04-20 14:44:11 +00005317 VG_(message)(Vg_DebugMsg,
sewardj23eb2fd2005-04-22 16:29:19 +00005318 " memcheck: auxmaps: %d auxmap entries (%dk, %dM) in use",
sewardj05a46732006-10-17 01:28:10 +00005319 n_auxmap_L2_nodes,
5320 n_auxmap_L2_nodes * 64,
5321 n_auxmap_L2_nodes / 16 );
sewardj23eb2fd2005-04-22 16:29:19 +00005322 VG_(message)(Vg_DebugMsg,
sewardj05a46732006-10-17 01:28:10 +00005323 " memcheck: auxmaps_L1: %lld searches, %lld cmps, ratio %lld:10",
5324 n_auxmap_L1_searches, n_auxmap_L1_cmps,
5325 (10ULL * n_auxmap_L1_cmps)
5326 / (n_auxmap_L1_searches ? n_auxmap_L1_searches : 1)
5327 );
5328 VG_(message)(Vg_DebugMsg,
5329 " memcheck: auxmaps_L2: %lld searches, %lld nodes",
5330 n_auxmap_L2_searches, n_auxmap_L2_nodes
5331 );
sewardj23eb2fd2005-04-22 16:29:19 +00005332
njndbf7ca72006-03-31 11:57:59 +00005333 print_SM_info("n_issued ", n_issued_SMs);
5334 print_SM_info("n_deissued ", n_deissued_SMs);
5335 print_SM_info("max_noaccess ", max_noaccess_SMs);
5336 print_SM_info("max_undefined", max_undefined_SMs);
5337 print_SM_info("max_defined ", max_defined_SMs);
5338 print_SM_info("max_non_DSM ", max_non_DSM_SMs);
njn1d0825f2006-03-27 11:37:07 +00005339
5340 // Three DSMs, plus the non-DSM ones
5341 max_SMs_szB = (3 + max_non_DSM_SMs) * sizeof(SecMap);
5342 // The 3*sizeof(Word) bytes is the AVL node metadata size.
5343 // The 4*sizeof(Word) bytes is the malloc metadata size.
5344 // Hardwiring these sizes in sucks, but I don't see how else to do it.
5345 max_secVBit_szB = max_secVBit_nodes *
5346 (sizeof(SecVBitNode) + 3*sizeof(Word) + 4*sizeof(Word));
5347 max_shmem_szB = sizeof(primary_map) + max_SMs_szB + max_secVBit_szB;
sewardj23eb2fd2005-04-22 16:29:19 +00005348
5349 VG_(message)(Vg_DebugMsg,
njn1d0825f2006-03-27 11:37:07 +00005350 " memcheck: max sec V bit nodes: %d (%dk, %dM)",
5351 max_secVBit_nodes, max_secVBit_szB / 1024,
5352 max_secVBit_szB / (1024 * 1024));
5353 VG_(message)(Vg_DebugMsg,
5354 " memcheck: set_sec_vbits8 calls: %llu (new: %llu, updates: %llu)",
5355 sec_vbits_new_nodes + sec_vbits_updates,
5356 sec_vbits_new_nodes, sec_vbits_updates );
5357 VG_(message)(Vg_DebugMsg,
5358 " memcheck: max shadow mem size: %dk, %dM",
5359 max_shmem_szB / 1024, max_shmem_szB / (1024 * 1024));
sewardj7cf4e6b2008-05-01 20:24:26 +00005360
5361 if (MC_(clo_mc_level) >= 3) {
5362 VG_(message)(Vg_DebugMsg,
5363 " ocacheL1: %,12lu refs %,12lu misses (%,lu lossage)",
5364 stats_ocacheL1_find,
5365 stats_ocacheL1_misses,
5366 stats_ocacheL1_lossage );
5367 VG_(message)(Vg_DebugMsg,
5368 " ocacheL1: %,12lu at 0 %,12lu at 1",
5369 stats_ocacheL1_find - stats_ocacheL1_misses
5370 - stats_ocacheL1_found_at_1
5371 - stats_ocacheL1_found_at_N,
5372 stats_ocacheL1_found_at_1 );
5373 VG_(message)(Vg_DebugMsg,
5374 " ocacheL1: %,12lu at 2+ %,12lu move-fwds",
5375 stats_ocacheL1_found_at_N,
5376 stats_ocacheL1_movefwds );
5377 VG_(message)(Vg_DebugMsg,
5378 " ocacheL1: %,12lu sizeB %,12lu useful",
5379 (UWord)sizeof(OCache),
5380 4 * OC_W32S_PER_LINE * OC_LINES_PER_SET * OC_N_SETS );
5381 VG_(message)(Vg_DebugMsg,
5382 " ocacheL2: %,12lu refs %,12lu misses",
5383 stats__ocacheL2_refs,
5384 stats__ocacheL2_misses );
5385 VG_(message)(Vg_DebugMsg,
5386 " ocacheL2: %,9lu max nodes %,9lu curr nodes",
5387 stats__ocacheL2_n_nodes_max,
5388 stats__ocacheL2_n_nodes );
5389 VG_(message)(Vg_DebugMsg,
5390 " niacache: %,12lu refs %,12lu misses",
5391 stats__nia_cache_queries, stats__nia_cache_misses);
sewardj9d624d12008-05-02 13:35:29 +00005392 } else {
5393 tl_assert(ocache == NULL);
5394 tl_assert(ocacheL2 == NULL);
sewardj7cf4e6b2008-05-01 20:24:26 +00005395 }
sewardj45d94cc2005-04-20 14:44:11 +00005396 }
5397
njn5c004e42002-11-18 11:04:50 +00005398 if (0) {
5399 VG_(message)(Vg_DebugMsg,
5400 "------ Valgrind's client block stats follow ---------------" );
nethercote8b76fe52004-11-08 19:20:09 +00005401 show_client_block_stats();
njn5c004e42002-11-18 11:04:50 +00005402 }
njn25e49d8e72002-09-23 09:36:25 +00005403}
5404
njn51d827b2005-05-09 01:02:08 +00005405static void mc_pre_clo_init(void)
5406{
5407 VG_(details_name) ("Memcheck");
5408 VG_(details_version) (NULL);
5409 VG_(details_description) ("a memory error detector");
5410 VG_(details_copyright_author)(
sewardj4d474d02008-02-11 11:34:59 +00005411 "Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.");
njn51d827b2005-05-09 01:02:08 +00005412 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj05a46732006-10-17 01:28:10 +00005413 VG_(details_avg_translation_sizeB) ( 556 );
njn51d827b2005-05-09 01:02:08 +00005414
5415 VG_(basic_tool_funcs) (mc_post_clo_init,
5416 MC_(instrument),
5417 mc_fini);
5418
sewardj81651dc2007-08-28 06:05:20 +00005419 VG_(needs_final_IR_tidy_pass) ( MC_(final_tidy) );
5420
5421
njn51d827b2005-05-09 01:02:08 +00005422 VG_(needs_core_errors) ();
sewardj7ce71662008-05-02 10:33:15 +00005423 VG_(needs_tool_errors) (MC_(eq_Error),
5424 MC_(pp_Error),
sewardj39f34232007-11-09 23:02:28 +00005425 True,/*show TIDs for errors*/
sewardj7ce71662008-05-02 10:33:15 +00005426 MC_(update_Error_extra),
5427 MC_(is_recognised_suppression),
5428 MC_(read_extra_suppression_info),
5429 MC_(error_matches_suppression),
5430 MC_(get_error_name),
5431 MC_(print_extra_suppression_info));
njn51d827b2005-05-09 01:02:08 +00005432 VG_(needs_libc_freeres) ();
njn1d0825f2006-03-27 11:37:07 +00005433 VG_(needs_command_line_options)(mc_process_cmd_line_options,
njn51d827b2005-05-09 01:02:08 +00005434 mc_print_usage,
5435 mc_print_debug_usage);
5436 VG_(needs_client_requests) (mc_handle_client_request);
5437 VG_(needs_sanity_checks) (mc_cheap_sanity_check,
5438 mc_expensive_sanity_check);
njn1d0825f2006-03-27 11:37:07 +00005439 VG_(needs_malloc_replacement) (MC_(malloc),
5440 MC_(__builtin_new),
5441 MC_(__builtin_vec_new),
5442 MC_(memalign),
5443 MC_(calloc),
5444 MC_(free),
5445 MC_(__builtin_delete),
5446 MC_(__builtin_vec_delete),
5447 MC_(realloc),
5448 MC_MALLOC_REDZONE_SZB );
njnca54af32006-04-16 10:25:43 +00005449 VG_(needs_xml_output) ();
njn51d827b2005-05-09 01:02:08 +00005450
njn1d0825f2006-03-27 11:37:07 +00005451 VG_(track_new_mem_startup) ( mc_new_mem_startup );
sewardj7cf4e6b2008-05-01 20:24:26 +00005452 VG_(track_new_mem_stack_signal)( make_mem_undefined_w_tid );
5453 VG_(track_new_mem_brk) ( make_mem_undefined_w_tid );
njn1d0825f2006-03-27 11:37:07 +00005454 VG_(track_new_mem_mmap) ( mc_new_mem_mmap );
njn51d827b2005-05-09 01:02:08 +00005455
njn1d0825f2006-03-27 11:37:07 +00005456 VG_(track_copy_mem_remap) ( MC_(copy_address_range_state) );
njn81623712005-10-07 04:48:37 +00005457
5458 // Nb: we don't do anything with mprotect. This means that V bits are
5459 // preserved if a program, for example, marks some memory as inaccessible
5460 // and then later marks it as accessible again.
5461 //
5462 // If an access violation occurs (eg. writing to read-only memory) we let
5463 // it fault and print an informative termination message. This doesn't
5464 // happen if the program catches the signal, though, which is bad. If we
5465 // had two A bits (for readability and writability) that were completely
5466 // distinct from V bits, then we could handle all this properly.
5467 VG_(track_change_mem_mprotect) ( NULL );
njn51d827b2005-05-09 01:02:08 +00005468
njndbf7ca72006-03-31 11:57:59 +00005469 VG_(track_die_mem_stack_signal)( MC_(make_mem_noaccess) );
5470 VG_(track_die_mem_brk) ( MC_(make_mem_noaccess) );
5471 VG_(track_die_mem_munmap) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005472
sewardj7cf4e6b2008-05-01 20:24:26 +00005473 /* Defer the specification of the new_mem_stack functions to the
5474 post_clo_init function, since we need to first parse the command
5475 line before deciding which set to use. */
njn51d827b2005-05-09 01:02:08 +00005476
sewardj7cf4e6b2008-05-01 20:24:26 +00005477# ifdef PERF_FAST_STACK
njn1d0825f2006-03-27 11:37:07 +00005478 VG_(track_die_mem_stack_4) ( mc_die_mem_stack_4 );
5479 VG_(track_die_mem_stack_8) ( mc_die_mem_stack_8 );
5480 VG_(track_die_mem_stack_12) ( mc_die_mem_stack_12 );
5481 VG_(track_die_mem_stack_16) ( mc_die_mem_stack_16 );
5482 VG_(track_die_mem_stack_32) ( mc_die_mem_stack_32 );
5483 VG_(track_die_mem_stack_112) ( mc_die_mem_stack_112 );
5484 VG_(track_die_mem_stack_128) ( mc_die_mem_stack_128 );
5485 VG_(track_die_mem_stack_144) ( mc_die_mem_stack_144 );
5486 VG_(track_die_mem_stack_160) ( mc_die_mem_stack_160 );
sewardj7cf4e6b2008-05-01 20:24:26 +00005487# endif
njn1d0825f2006-03-27 11:37:07 +00005488 VG_(track_die_mem_stack) ( mc_die_mem_stack );
njn51d827b2005-05-09 01:02:08 +00005489
njndbf7ca72006-03-31 11:57:59 +00005490 VG_(track_ban_mem_stack) ( MC_(make_mem_noaccess) );
njn51d827b2005-05-09 01:02:08 +00005491
njndbf7ca72006-03-31 11:57:59 +00005492 VG_(track_pre_mem_read) ( check_mem_is_defined );
5493 VG_(track_pre_mem_read_asciiz) ( check_mem_is_defined_asciiz );
5494 VG_(track_pre_mem_write) ( check_mem_is_addressable );
njn1d0825f2006-03-27 11:37:07 +00005495 VG_(track_post_mem_write) ( mc_post_mem_write );
njn51d827b2005-05-09 01:02:08 +00005496
sewardj7cf4e6b2008-05-01 20:24:26 +00005497 if (MC_(clo_mc_level) >= 2)
njn1d0825f2006-03-27 11:37:07 +00005498 VG_(track_pre_reg_read) ( mc_pre_reg_read );
njn51d827b2005-05-09 01:02:08 +00005499
njn1d0825f2006-03-27 11:37:07 +00005500 VG_(track_post_reg_write) ( mc_post_reg_write );
5501 VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
njn51d827b2005-05-09 01:02:08 +00005502
5503 init_shadow_memory();
sewardj3f94a7d2007-08-25 07:19:08 +00005504 MC_(malloc_list) = VG_(HT_construct)( "MC_(malloc_list)" );
5505 MC_(mempool_list) = VG_(HT_construct)( "MC_(mempool_list)" );
njn1d0825f2006-03-27 11:37:07 +00005506 init_prof_mem();
njn51d827b2005-05-09 01:02:08 +00005507
5508 tl_assert( mc_expensive_sanity_check() );
njn1d0825f2006-03-27 11:37:07 +00005509
5510 // {LOADV,STOREV}[8421] will all fail horribly if this isn't true.
5511 tl_assert(sizeof(UWord) == sizeof(Addr));
sewardj05a46732006-10-17 01:28:10 +00005512 // Call me paranoid. I don't care.
5513 tl_assert(sizeof(void*) == sizeof(Addr));
njn1d0825f2006-03-27 11:37:07 +00005514
5515 // BYTES_PER_SEC_VBIT_NODE must be a power of two.
5516 tl_assert(-1 != VG_(log2)(BYTES_PER_SEC_VBIT_NODE));
sewardj7cf4e6b2008-05-01 20:24:26 +00005517
sewardj9d624d12008-05-02 13:35:29 +00005518 /* This is small. Always initialise it. */
sewardj7cf4e6b2008-05-01 20:24:26 +00005519 init_nia_to_ecu_cache();
sewardj7244e712008-05-02 12:35:48 +00005520
sewardj9d624d12008-05-02 13:35:29 +00005521 /* We can't initialise ocache/ocacheL2 yet, since we don't know if
5522 we need to, since the command line args haven't been processed
5523 yet. Hence defer it to mc_post_clo_init. */
5524 tl_assert(ocache == NULL);
5525 tl_assert(ocacheL2 == NULL);
5526
sewardj7244e712008-05-02 12:35:48 +00005527 /* Check some important stuff. See extensive comments above
5528 re UNALIGNED_OR_HIGH for background. */
5529# if VG_WORDSIZE == 4
5530 tl_assert(sizeof(void*) == 4);
5531 tl_assert(sizeof(Addr) == 4);
5532 tl_assert(sizeof(UWord) == 4);
5533 tl_assert(sizeof(Word) == 4);
5534 tl_assert(MAX_PRIMARY_ADDRESS == 0xFFFFFFFFUL);
5535 tl_assert(MASK(1) == 0UL);
5536 tl_assert(MASK(2) == 1UL);
5537 tl_assert(MASK(4) == 3UL);
5538 tl_assert(MASK(8) == 7UL);
5539# else
5540 tl_assert(VG_WORDSIZE == 8);
5541 tl_assert(sizeof(void*) == 8);
5542 tl_assert(sizeof(Addr) == 8);
5543 tl_assert(sizeof(UWord) == 8);
5544 tl_assert(sizeof(Word) == 8);
5545 tl_assert(MAX_PRIMARY_ADDRESS == 0x7FFFFFFFFULL);
5546 tl_assert(MASK(1) == 0xFFFFFFF800000000ULL);
5547 tl_assert(MASK(2) == 0xFFFFFFF800000001ULL);
5548 tl_assert(MASK(4) == 0xFFFFFFF800000003ULL);
5549 tl_assert(MASK(8) == 0xFFFFFFF800000007ULL);
5550# endif
njn51d827b2005-05-09 01:02:08 +00005551}
5552
sewardj45f4e7c2005-09-27 19:20:21 +00005553VG_DETERMINE_INTERFACE_VERSION(mc_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +00005554
njn25e49d8e72002-09-23 09:36:25 +00005555/*--------------------------------------------------------------------*/
sewardj7ce71662008-05-02 10:33:15 +00005556/*--- end mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005557/*--------------------------------------------------------------------*/