blob: c4cef5b733226813824b1007a70d0402ab7ab4d8 [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
njn53612422005-03-12 16:22:54 +000012 Copyright (C) 2000-2005 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
njn25cac76cb2002-09-23 11:21:57 +000033#include "mc_include.h"
34#include "memcheck.h" /* for client requests */
njn25e49d8e72002-09-23 09:36:25 +000035//#include "vg_profile.c"
36
37/* Define to debug the mem audit system. */
38/* #define VG_DEBUG_MEMORY */
39
njn25e49d8e72002-09-23 09:36:25 +000040#define DEBUG(fmt, args...) //VG_(printf)(fmt, ## args)
41
42/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000043/*--- Low-level support for memory checking. ---*/
44/*------------------------------------------------------------*/
45
46/* All reads and writes are checked against a memory map, which
47 records the state of all memory in the process. The memory map is
48 organised like this:
49
50 The top 16 bits of an address are used to index into a top-level
51 map table, containing 65536 entries. Each entry is a pointer to a
52 second-level map, which records the accesibililty and validity
53 permissions for the 65536 bytes indexed by the lower 16 bits of the
54 address. Each byte is represented by nine bits, one indicating
55 accessibility, the other eight validity. So each second-level map
56 contains 73728 bytes. This two-level arrangement conveniently
57 divides the 4G address space into 64k lumps, each size 64k bytes.
58
59 All entries in the primary (top-level) map must point to a valid
60 secondary (second-level) map. Since most of the 4G of address
61 space will not be in use -- ie, not mapped at all -- there is a
62 distinguished secondary map, which indicates `not addressible and
63 not valid' writeable for all bytes. Entries in the primary map for
64 which the entire 64k is not in use at all point at this
65 distinguished map.
66
67 [...] lots of stuff deleted due to out of date-ness
68
69 As a final optimisation, the alignment and address checks for
70 4-byte loads and stores are combined in a neat way. The primary
71 map is extended to have 262144 entries (2^18), rather than 2^16.
72 The top 3/4 of these entries are permanently set to the
73 distinguished secondary map. For a 4-byte load/store, the
74 top-level map is indexed not with (addr >> 16) but instead f(addr),
75 where
76
77 f( XXXX XXXX XXXX XXXX ____ ____ ____ __YZ )
78 = ____ ____ ____ __YZ XXXX XXXX XXXX XXXX or
79 = ____ ____ ____ __ZY XXXX XXXX XXXX XXXX
80
81 ie the lowest two bits are placed above the 16 high address bits.
82 If either of these two bits are nonzero, the address is misaligned;
83 this will select a secondary map from the upper 3/4 of the primary
84 map. Because this is always the distinguished secondary map, a
85 (bogus) address check failure will result. The failure handling
86 code can then figure out whether this is a genuine addr check
87 failure or whether it is a possibly-legitimate access at a
88 misaligned address.
89*/
90
91
92/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000093/*--- Function declarations. ---*/
94/*------------------------------------------------------------*/
95
sewardj95448072004-11-22 20:19:51 +000096static ULong mc_rd_V8_SLOWLY ( Addr a );
97static UInt mc_rd_V4_SLOWLY ( Addr a );
98static UInt mc_rd_V2_SLOWLY ( Addr a );
99static UInt mc_rd_V1_SLOWLY ( Addr a );
100
101static void mc_wr_V8_SLOWLY ( Addr a, ULong vbytes );
njn5c004e42002-11-18 11:04:50 +0000102static void mc_wr_V4_SLOWLY ( Addr a, UInt vbytes );
103static void mc_wr_V2_SLOWLY ( Addr a, UInt vbytes );
104static void mc_wr_V1_SLOWLY ( Addr a, UInt vbytes );
sewardj95448072004-11-22 20:19:51 +0000105
njn25e49d8e72002-09-23 09:36:25 +0000106/*------------------------------------------------------------*/
107/*--- Data defns. ---*/
108/*------------------------------------------------------------*/
109
110typedef
111 struct {
112 UChar abits[8192];
113 UChar vbyte[65536];
114 }
115 SecMap;
116
117static SecMap* primary_map[ /*65536*/ 262144 ];
118static SecMap distinguished_secondary_map;
119
njn25e49d8e72002-09-23 09:36:25 +0000120static void init_shadow_memory ( void )
121{
122 Int i;
123
124 for (i = 0; i < 8192; i++) /* Invalid address */
125 distinguished_secondary_map.abits[i] = VGM_BYTE_INVALID;
126 for (i = 0; i < 65536; i++) /* Invalid Value */
127 distinguished_secondary_map.vbyte[i] = VGM_BYTE_INVALID;
128
129 /* These entries gradually get overwritten as the used address
130 space expands. */
131 for (i = 0; i < 65536; i++)
132 primary_map[i] = &distinguished_secondary_map;
133
134 /* These ones should never change; it's a bug in Valgrind if they do. */
135 for (i = 65536; i < 262144; i++)
136 primary_map[i] = &distinguished_secondary_map;
137}
138
njn25e49d8e72002-09-23 09:36:25 +0000139/*------------------------------------------------------------*/
140/*--- Basic bitmap management, reading and writing. ---*/
141/*------------------------------------------------------------*/
142
143/* Allocate and initialise a secondary map. */
144
145static SecMap* alloc_secondary_map ( __attribute__ ((unused))
146 Char* caller )
147{
148 SecMap* map;
149 UInt i;
150 PROF_EVENT(10);
151
152 /* Mark all bytes as invalid access and invalid value. */
fitzhardinge98abfc72003-12-16 02:05:15 +0000153 map = (SecMap *)VG_(shadow_alloc)(sizeof(SecMap));
njn25e49d8e72002-09-23 09:36:25 +0000154
155 for (i = 0; i < 8192; i++)
156 map->abits[i] = VGM_BYTE_INVALID; /* Invalid address */
157 for (i = 0; i < 65536; i++)
158 map->vbyte[i] = VGM_BYTE_INVALID; /* Invalid Value */
159
160 /* VG_(printf)("ALLOC_2MAP(%s)\n", caller ); */
161 return map;
162}
163
164
165/* Basic reading/writing of the bitmaps, for byte-sized accesses. */
166
167static __inline__ UChar get_abit ( Addr a )
168{
169 SecMap* sm = primary_map[a >> 16];
170 UInt sm_off = a & 0xFFFF;
171 PROF_EVENT(20);
172# if 0
173 if (IS_DISTINGUISHED_SM(sm))
174 VG_(message)(Vg_DebugMsg,
175 "accessed distinguished 2ndary (A)map! 0x%x\n", a);
176# endif
177 return BITARR_TEST(sm->abits, sm_off)
178 ? VGM_BIT_INVALID : VGM_BIT_VALID;
179}
180
181static __inline__ UChar get_vbyte ( Addr a )
182{
183 SecMap* sm = primary_map[a >> 16];
184 UInt sm_off = a & 0xFFFF;
185 PROF_EVENT(21);
186# if 0
187 if (IS_DISTINGUISHED_SM(sm))
188 VG_(message)(Vg_DebugMsg,
189 "accessed distinguished 2ndary (V)map! 0x%x\n", a);
190# endif
191 return sm->vbyte[sm_off];
192}
193
sewardj56867352003-10-12 10:27:06 +0000194static /* __inline__ */ void set_abit ( Addr a, UChar abit )
njn25e49d8e72002-09-23 09:36:25 +0000195{
196 SecMap* sm;
197 UInt sm_off;
198 PROF_EVENT(22);
199 ENSURE_MAPPABLE(a, "set_abit");
200 sm = primary_map[a >> 16];
201 sm_off = a & 0xFFFF;
202 if (abit)
203 BITARR_SET(sm->abits, sm_off);
204 else
205 BITARR_CLEAR(sm->abits, sm_off);
206}
207
208static __inline__ void set_vbyte ( Addr a, UChar vbyte )
209{
210 SecMap* sm;
211 UInt sm_off;
212 PROF_EVENT(23);
213 ENSURE_MAPPABLE(a, "set_vbyte");
214 sm = primary_map[a >> 16];
215 sm_off = a & 0xFFFF;
216 sm->vbyte[sm_off] = vbyte;
217}
218
219
220/* Reading/writing of the bitmaps, for aligned word-sized accesses. */
221
222static __inline__ UChar get_abits4_ALIGNED ( Addr a )
223{
224 SecMap* sm;
225 UInt sm_off;
226 UChar abits8;
227 PROF_EVENT(24);
228# ifdef VG_DEBUG_MEMORY
njnedfa0f62004-11-30 18:08:05 +0000229 tl_assert(IS_4_ALIGNED(a));
njn25e49d8e72002-09-23 09:36:25 +0000230# endif
231 sm = primary_map[a >> 16];
232 sm_off = a & 0xFFFF;
233 abits8 = sm->abits[sm_off >> 3];
234 abits8 >>= (a & 4 /* 100b */); /* a & 4 is either 0 or 4 */
235 abits8 &= 0x0F;
236 return abits8;
237}
238
239static UInt __inline__ get_vbytes4_ALIGNED ( Addr a )
240{
241 SecMap* sm = primary_map[a >> 16];
242 UInt sm_off = a & 0xFFFF;
243 PROF_EVENT(25);
244# ifdef VG_DEBUG_MEMORY
njnedfa0f62004-11-30 18:08:05 +0000245 tl_assert(IS_4_ALIGNED(a));
njn25e49d8e72002-09-23 09:36:25 +0000246# endif
247 return ((UInt*)(sm->vbyte))[sm_off >> 2];
248}
249
250
sewardjee070842003-07-05 17:53:55 +0000251static void __inline__ set_vbytes4_ALIGNED ( Addr a, UInt vbytes )
252{
253 SecMap* sm;
254 UInt sm_off;
255 ENSURE_MAPPABLE(a, "set_vbytes4_ALIGNED");
256 sm = primary_map[a >> 16];
257 sm_off = a & 0xFFFF;
258 PROF_EVENT(23);
259# ifdef VG_DEBUG_MEMORY
njnedfa0f62004-11-30 18:08:05 +0000260 tl_assert(IS_4_ALIGNED(a));
sewardjee070842003-07-05 17:53:55 +0000261# endif
262 ((UInt*)(sm->vbyte))[sm_off >> 2] = vbytes;
263}
264
265
njn25e49d8e72002-09-23 09:36:25 +0000266/*------------------------------------------------------------*/
267/*--- Setting permissions over address ranges. ---*/
268/*------------------------------------------------------------*/
269
nethercote451eae92004-11-02 13:06:32 +0000270static void set_address_range_perms ( Addr a, SizeT len,
njn25e49d8e72002-09-23 09:36:25 +0000271 UInt example_a_bit,
272 UInt example_v_bit )
273{
274 UChar vbyte, abyte8;
275 UInt vword4, sm_off;
276 SecMap* sm;
277
278 PROF_EVENT(30);
279
280 if (len == 0)
281 return;
282
nethercotea66033c2004-03-08 15:37:58 +0000283 if (VG_(clo_verbosity) > 0) {
284 if (len > 100 * 1000 * 1000) {
285 VG_(message)(Vg_UserMsg,
286 "Warning: set address range perms: "
287 "large range %u, a %d, v %d",
288 len, example_a_bit, example_v_bit );
289 }
njn25e49d8e72002-09-23 09:36:25 +0000290 }
291
292 VGP_PUSHCC(VgpSetMem);
293
294 /* Requests to change permissions of huge address ranges may
295 indicate bugs in our machinery. 30,000,000 is arbitrary, but so
296 far all legitimate requests have fallen beneath that size. */
297 /* 4 Mar 02: this is just stupid; get rid of it. */
njnca82cc02004-11-22 17:18:48 +0000298 /* tl_assert(len < 30000000); */
njn25e49d8e72002-09-23 09:36:25 +0000299
300 /* Check the permissions make sense. */
njnca82cc02004-11-22 17:18:48 +0000301 tl_assert(example_a_bit == VGM_BIT_VALID
njn25e49d8e72002-09-23 09:36:25 +0000302 || example_a_bit == VGM_BIT_INVALID);
njnca82cc02004-11-22 17:18:48 +0000303 tl_assert(example_v_bit == VGM_BIT_VALID
njn25e49d8e72002-09-23 09:36:25 +0000304 || example_v_bit == VGM_BIT_INVALID);
305 if (example_a_bit == VGM_BIT_INVALID)
njnca82cc02004-11-22 17:18:48 +0000306 tl_assert(example_v_bit == VGM_BIT_INVALID);
njn25e49d8e72002-09-23 09:36:25 +0000307
308 /* The validity bits to write. */
309 vbyte = example_v_bit==VGM_BIT_VALID
310 ? VGM_BYTE_VALID : VGM_BYTE_INVALID;
311
312 /* In order that we can charge through the address space at 8
313 bytes/main-loop iteration, make up some perms. */
314 abyte8 = (example_a_bit << 7)
315 | (example_a_bit << 6)
316 | (example_a_bit << 5)
317 | (example_a_bit << 4)
318 | (example_a_bit << 3)
319 | (example_a_bit << 2)
320 | (example_a_bit << 1)
321 | (example_a_bit << 0);
322 vword4 = (vbyte << 24) | (vbyte << 16) | (vbyte << 8) | vbyte;
323
324# ifdef VG_DEBUG_MEMORY
325 /* Do it ... */
326 while (True) {
327 PROF_EVENT(31);
328 if (len == 0) break;
329 set_abit ( a, example_a_bit );
330 set_vbyte ( a, vbyte );
331 a++;
332 len--;
333 }
334
335# else
336 /* Slowly do parts preceding 8-byte alignment. */
337 while (True) {
338 PROF_EVENT(31);
339 if (len == 0) break;
340 if ((a % 8) == 0) break;
341 set_abit ( a, example_a_bit );
342 set_vbyte ( a, vbyte );
343 a++;
344 len--;
345 }
346
347 if (len == 0) {
348 VGP_POPCC(VgpSetMem);
349 return;
350 }
njnca82cc02004-11-22 17:18:48 +0000351 tl_assert((a % 8) == 0 && len > 0);
njn25e49d8e72002-09-23 09:36:25 +0000352
353 /* Once aligned, go fast. */
354 while (True) {
355 PROF_EVENT(32);
356 if (len < 8) break;
357 ENSURE_MAPPABLE(a, "set_address_range_perms(fast)");
358 sm = primary_map[a >> 16];
359 sm_off = a & 0xFFFF;
360 sm->abits[sm_off >> 3] = abyte8;
361 ((UInt*)(sm->vbyte))[(sm_off >> 2) + 0] = vword4;
362 ((UInt*)(sm->vbyte))[(sm_off >> 2) + 1] = vword4;
363 a += 8;
364 len -= 8;
365 }
366
367 if (len == 0) {
368 VGP_POPCC(VgpSetMem);
369 return;
370 }
njnca82cc02004-11-22 17:18:48 +0000371 tl_assert((a % 8) == 0 && len > 0 && len < 8);
njn25e49d8e72002-09-23 09:36:25 +0000372
373 /* Finish the upper fragment. */
374 while (True) {
375 PROF_EVENT(33);
376 if (len == 0) break;
377 set_abit ( a, example_a_bit );
378 set_vbyte ( a, vbyte );
379 a++;
380 len--;
381 }
382# endif
383
384 /* Check that zero page and highest page have not been written to
385 -- this could happen with buggy syscall wrappers. Today
386 (2001-04-26) had precisely such a problem with __NR_setitimer. */
njn26f02512004-11-22 18:33:15 +0000387 tl_assert(TL_(cheap_sanity_check)());
njn25e49d8e72002-09-23 09:36:25 +0000388 VGP_POPCC(VgpSetMem);
389}
390
391/* Set permissions for address ranges ... */
392
nethercote8b76fe52004-11-08 19:20:09 +0000393static void mc_make_noaccess ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +0000394{
395 PROF_EVENT(35);
nethercote8b76fe52004-11-08 19:20:09 +0000396 DEBUG("mc_make_noaccess(%p, %llu)\n", a, (ULong)len);
njn25e49d8e72002-09-23 09:36:25 +0000397 set_address_range_perms ( a, len, VGM_BIT_INVALID, VGM_BIT_INVALID );
398}
399
nethercote8b76fe52004-11-08 19:20:09 +0000400static void mc_make_writable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +0000401{
402 PROF_EVENT(36);
nethercote8b76fe52004-11-08 19:20:09 +0000403 DEBUG("mc_make_writable(%p, %llu)\n", a, (ULong)len);
njn25e49d8e72002-09-23 09:36:25 +0000404 set_address_range_perms ( a, len, VGM_BIT_VALID, VGM_BIT_INVALID );
405}
406
nethercote8b76fe52004-11-08 19:20:09 +0000407static void mc_make_readable ( Addr a, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +0000408{
409 PROF_EVENT(37);
nethercote8b76fe52004-11-08 19:20:09 +0000410 DEBUG("mc_make_readable(%p, %llu)\n", a, (ULong)len);
njn25e49d8e72002-09-23 09:36:25 +0000411 set_address_range_perms ( a, len, VGM_BIT_VALID, VGM_BIT_VALID );
412}
413
njn9b007f62003-04-07 14:40:25 +0000414static __inline__
415void make_aligned_word_writable(Addr a)
416{
417 SecMap* sm;
418 UInt sm_off;
419 UChar mask;
njn25e49d8e72002-09-23 09:36:25 +0000420
njn9b007f62003-04-07 14:40:25 +0000421 VGP_PUSHCC(VgpESPAdj);
422 ENSURE_MAPPABLE(a, "make_aligned_word_writable");
423 sm = primary_map[a >> 16];
424 sm_off = a & 0xFFFF;
425 ((UInt*)(sm->vbyte))[sm_off >> 2] = VGM_WORD_INVALID;
426 mask = 0x0F;
427 mask <<= (a & 4 /* 100b */); /* a & 4 is either 0 or 4 */
428 /* mask now contains 1s where we wish to make address bits invalid (0s). */
429 sm->abits[sm_off >> 3] &= ~mask;
430 VGP_POPCC(VgpESPAdj);
431}
432
433static __inline__
434void make_aligned_word_noaccess(Addr a)
435{
436 SecMap* sm;
437 UInt sm_off;
438 UChar mask;
439
440 VGP_PUSHCC(VgpESPAdj);
441 ENSURE_MAPPABLE(a, "make_aligned_word_noaccess");
442 sm = primary_map[a >> 16];
443 sm_off = a & 0xFFFF;
444 ((UInt*)(sm->vbyte))[sm_off >> 2] = VGM_WORD_INVALID;
445 mask = 0x0F;
446 mask <<= (a & 4 /* 100b */); /* a & 4 is either 0 or 4 */
447 /* mask now contains 1s where we wish to make address bits invalid (1s). */
448 sm->abits[sm_off >> 3] |= mask;
449 VGP_POPCC(VgpESPAdj);
450}
451
452/* Nb: by "aligned" here we mean 8-byte aligned */
453static __inline__
454void make_aligned_doubleword_writable(Addr a)
455{
456 SecMap* sm;
457 UInt sm_off;
458
459 VGP_PUSHCC(VgpESPAdj);
460 ENSURE_MAPPABLE(a, "make_aligned_doubleword_writable");
461 sm = primary_map[a >> 16];
462 sm_off = a & 0xFFFF;
463 sm->abits[sm_off >> 3] = VGM_BYTE_VALID;
464 ((UInt*)(sm->vbyte))[(sm_off >> 2) + 0] = VGM_WORD_INVALID;
465 ((UInt*)(sm->vbyte))[(sm_off >> 2) + 1] = VGM_WORD_INVALID;
466 VGP_POPCC(VgpESPAdj);
467}
468
469static __inline__
470void make_aligned_doubleword_noaccess(Addr a)
471{
472 SecMap* sm;
473 UInt sm_off;
474
475 VGP_PUSHCC(VgpESPAdj);
476 ENSURE_MAPPABLE(a, "make_aligned_doubleword_noaccess");
477 sm = primary_map[a >> 16];
478 sm_off = a & 0xFFFF;
479 sm->abits[sm_off >> 3] = VGM_BYTE_INVALID;
480 ((UInt*)(sm->vbyte))[(sm_off >> 2) + 0] = VGM_WORD_INVALID;
481 ((UInt*)(sm->vbyte))[(sm_off >> 2) + 1] = VGM_WORD_INVALID;
482 VGP_POPCC(VgpESPAdj);
483}
484
485/* The %esp update handling functions */
486ESP_UPDATE_HANDLERS ( make_aligned_word_writable,
487 make_aligned_word_noaccess,
488 make_aligned_doubleword_writable,
489 make_aligned_doubleword_noaccess,
nethercote8b76fe52004-11-08 19:20:09 +0000490 mc_make_writable,
491 mc_make_noaccess
njn9b007f62003-04-07 14:40:25 +0000492 );
493
494/* Block-copy permissions (needed for implementing realloc()). */
nethercote451eae92004-11-02 13:06:32 +0000495static void mc_copy_address_range_state ( Addr src, Addr dst, SizeT len )
njn25e49d8e72002-09-23 09:36:25 +0000496{
nethercote451eae92004-11-02 13:06:32 +0000497 SizeT i;
njn25e49d8e72002-09-23 09:36:25 +0000498
njn5c004e42002-11-18 11:04:50 +0000499 DEBUG("mc_copy_address_range_state\n");
njn25e49d8e72002-09-23 09:36:25 +0000500
501 PROF_EVENT(40);
502 for (i = 0; i < len; i++) {
503 UChar abit = get_abit ( src+i );
504 UChar vbyte = get_vbyte ( src+i );
505 PROF_EVENT(41);
506 set_abit ( dst+i, abit );
507 set_vbyte ( dst+i, vbyte );
508 }
509}
510
nethercote8b76fe52004-11-08 19:20:09 +0000511/*------------------------------------------------------------*/
512/*--- Checking memory ---*/
513/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000514
515/* Check permissions for address range. If inadequate permissions
516 exist, *bad_addr is set to the offending address, so the caller can
517 know what it is. */
518
sewardjecf8e102003-07-12 12:11:39 +0000519/* Returns True if [a .. a+len) is not addressible. Otherwise,
520 returns False, and if bad_addr is non-NULL, sets *bad_addr to
521 indicate the lowest failing address. Functions below are
522 similar. */
nethercote8b76fe52004-11-08 19:20:09 +0000523static Bool mc_check_noaccess ( Addr a, SizeT len, Addr* bad_addr )
sewardjecf8e102003-07-12 12:11:39 +0000524{
nethercote451eae92004-11-02 13:06:32 +0000525 SizeT i;
sewardjecf8e102003-07-12 12:11:39 +0000526 UChar abit;
527 PROF_EVENT(42);
528 for (i = 0; i < len; i++) {
529 PROF_EVENT(43);
530 abit = get_abit(a);
531 if (abit == VGM_BIT_VALID) {
532 if (bad_addr != NULL) *bad_addr = a;
533 return False;
534 }
535 a++;
536 }
537 return True;
538}
539
nethercote8b76fe52004-11-08 19:20:09 +0000540static Bool mc_check_writable ( Addr a, SizeT len, Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +0000541{
nethercote451eae92004-11-02 13:06:32 +0000542 SizeT i;
njn25e49d8e72002-09-23 09:36:25 +0000543 UChar abit;
544 PROF_EVENT(42);
545 for (i = 0; i < len; i++) {
546 PROF_EVENT(43);
547 abit = get_abit(a);
548 if (abit == VGM_BIT_INVALID) {
549 if (bad_addr != NULL) *bad_addr = a;
550 return False;
551 }
552 a++;
553 }
554 return True;
555}
556
nethercote8b76fe52004-11-08 19:20:09 +0000557typedef enum {
558 MC_Ok = 5, MC_AddrErr = 6, MC_ValueErr = 7
559} MC_ReadResult;
560
561static MC_ReadResult mc_check_readable ( Addr a, SizeT len, Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +0000562{
nethercote451eae92004-11-02 13:06:32 +0000563 SizeT i;
njn25e49d8e72002-09-23 09:36:25 +0000564 UChar abit;
565 UChar vbyte;
566
567 PROF_EVENT(44);
nethercote8b76fe52004-11-08 19:20:09 +0000568 DEBUG("mc_check_readable\n");
njn25e49d8e72002-09-23 09:36:25 +0000569 for (i = 0; i < len; i++) {
570 abit = get_abit(a);
571 vbyte = get_vbyte(a);
572 PROF_EVENT(45);
nethercote8b76fe52004-11-08 19:20:09 +0000573 // Report addressability errors in preference to definedness errors
574 // by checking the A bits first.
575 if (abit != VGM_BIT_VALID) {
njn25e49d8e72002-09-23 09:36:25 +0000576 if (bad_addr != NULL) *bad_addr = a;
nethercote8b76fe52004-11-08 19:20:09 +0000577 return MC_AddrErr;
578 }
579 if (vbyte != VGM_BYTE_VALID) {
580 if (bad_addr != NULL) *bad_addr = a;
581 return MC_ValueErr;
njn25e49d8e72002-09-23 09:36:25 +0000582 }
583 a++;
584 }
nethercote8b76fe52004-11-08 19:20:09 +0000585 return MC_Ok;
njn25e49d8e72002-09-23 09:36:25 +0000586}
587
588
589/* Check a zero-terminated ascii string. Tricky -- don't want to
590 examine the actual bytes, to find the end, until we're sure it is
591 safe to do so. */
592
njn9b007f62003-04-07 14:40:25 +0000593static Bool mc_check_readable_asciiz ( Addr a, Addr* bad_addr )
njn25e49d8e72002-09-23 09:36:25 +0000594{
595 UChar abit;
596 UChar vbyte;
597 PROF_EVENT(46);
njn5c004e42002-11-18 11:04:50 +0000598 DEBUG("mc_check_readable_asciiz\n");
njn25e49d8e72002-09-23 09:36:25 +0000599 while (True) {
600 PROF_EVENT(47);
601 abit = get_abit(a);
602 vbyte = get_vbyte(a);
nethercote8b76fe52004-11-08 19:20:09 +0000603 // As in mc_check_readable(), check A bits first
604 if (abit != VGM_BIT_VALID) {
njn25e49d8e72002-09-23 09:36:25 +0000605 if (bad_addr != NULL) *bad_addr = a;
nethercote8b76fe52004-11-08 19:20:09 +0000606 return MC_AddrErr;
607 }
608 if (vbyte != VGM_BYTE_VALID) {
609 if (bad_addr != NULL) *bad_addr = a;
610 return MC_ValueErr;
njn25e49d8e72002-09-23 09:36:25 +0000611 }
612 /* Ok, a is safe to read. */
nethercote8b76fe52004-11-08 19:20:09 +0000613 if (* ((UChar*)a) == 0) return MC_Ok;
njn25e49d8e72002-09-23 09:36:25 +0000614 a++;
615 }
616}
617
618
619/*------------------------------------------------------------*/
620/*--- Memory event handlers ---*/
621/*------------------------------------------------------------*/
622
njn25e49d8e72002-09-23 09:36:25 +0000623static
njn72718642003-07-24 08:45:32 +0000624void mc_check_is_writable ( CorePart part, ThreadId tid, Char* s,
nethercote451eae92004-11-02 13:06:32 +0000625 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +0000626{
627 Bool ok;
628 Addr bad_addr;
629
630 VGP_PUSHCC(VgpCheckMem);
631
632 /* VG_(message)(Vg_DebugMsg,"check is writable: %x .. %x",
633 base,base+size-1); */
nethercote8b76fe52004-11-08 19:20:09 +0000634 ok = mc_check_writable ( base, size, &bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000635 if (!ok) {
636 switch (part) {
637 case Vg_CoreSysCall:
nethercote8b76fe52004-11-08 19:20:09 +0000638 MAC_(record_param_error) ( tid, bad_addr, /*isReg*/False,
639 /*isUnaddr*/True, s );
njn25e49d8e72002-09-23 09:36:25 +0000640 break;
641
642 case Vg_CorePThread:
643 case Vg_CoreSignal:
nethercote8b76fe52004-11-08 19:20:09 +0000644 MAC_(record_core_mem_error)( tid, /*isUnaddr*/True, s );
njn25e49d8e72002-09-23 09:36:25 +0000645 break;
646
647 default:
njn67993252004-11-22 18:02:32 +0000648 VG_(tool_panic)("mc_check_is_writable: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +0000649 }
650 }
651
652 VGP_POPCC(VgpCheckMem);
653}
654
655static
njn72718642003-07-24 08:45:32 +0000656void mc_check_is_readable ( CorePart part, ThreadId tid, Char* s,
nethercote451eae92004-11-02 13:06:32 +0000657 Addr base, SizeT size )
njn25e49d8e72002-09-23 09:36:25 +0000658{
njn25e49d8e72002-09-23 09:36:25 +0000659 Addr bad_addr;
nethercote8b76fe52004-11-08 19:20:09 +0000660 MC_ReadResult res;
njn25e49d8e72002-09-23 09:36:25 +0000661
662 VGP_PUSHCC(VgpCheckMem);
663
664 /* VG_(message)(Vg_DebugMsg,"check is readable: %x .. %x",
665 base,base+size-1); */
nethercote8b76fe52004-11-08 19:20:09 +0000666 res = mc_check_readable ( base, size, &bad_addr );
667 if (MC_Ok != res) {
668 Bool isUnaddr = ( MC_AddrErr == res ? True : False );
669
njn25e49d8e72002-09-23 09:36:25 +0000670 switch (part) {
671 case Vg_CoreSysCall:
nethercote8b76fe52004-11-08 19:20:09 +0000672 MAC_(record_param_error) ( tid, bad_addr, /*isReg*/False,
673 isUnaddr, s );
njn25e49d8e72002-09-23 09:36:25 +0000674 break;
675
676 case Vg_CorePThread:
nethercote8b76fe52004-11-08 19:20:09 +0000677 MAC_(record_core_mem_error)( tid, isUnaddr, s );
njn25e49d8e72002-09-23 09:36:25 +0000678 break;
679
680 /* If we're being asked to jump to a silly address, record an error
681 message before potentially crashing the entire system. */
682 case Vg_CoreTranslate:
njn72718642003-07-24 08:45:32 +0000683 MAC_(record_jump_error)( tid, bad_addr );
njn25e49d8e72002-09-23 09:36:25 +0000684 break;
685
686 default:
njn67993252004-11-22 18:02:32 +0000687 VG_(tool_panic)("mc_check_is_readable: unexpected CorePart");
njn25e49d8e72002-09-23 09:36:25 +0000688 }
689 }
690 VGP_POPCC(VgpCheckMem);
691}
692
693static
njn72718642003-07-24 08:45:32 +0000694void mc_check_is_readable_asciiz ( CorePart part, ThreadId tid,
njn5c004e42002-11-18 11:04:50 +0000695 Char* s, Addr str )
njn25e49d8e72002-09-23 09:36:25 +0000696{
nethercote8b76fe52004-11-08 19:20:09 +0000697 MC_ReadResult res;
njn25e49d8e72002-09-23 09:36:25 +0000698 Addr bad_addr;
699 /* VG_(message)(Vg_DebugMsg,"check is readable asciiz: 0x%x",str); */
700
701 VGP_PUSHCC(VgpCheckMem);
702
njnca82cc02004-11-22 17:18:48 +0000703 tl_assert(part == Vg_CoreSysCall);
nethercote8b76fe52004-11-08 19:20:09 +0000704 res = mc_check_readable_asciiz ( (Addr)str, &bad_addr );
705 if (MC_Ok != res) {
706 Bool isUnaddr = ( MC_AddrErr == res ? True : False );
707 MAC_(record_param_error) ( tid, bad_addr, /*isReg*/False, isUnaddr, s );
njn25e49d8e72002-09-23 09:36:25 +0000708 }
709
710 VGP_POPCC(VgpCheckMem);
711}
712
713
714static
nethercote451eae92004-11-02 13:06:32 +0000715void mc_new_mem_startup( Addr a, SizeT len, Bool rr, Bool ww, Bool xx )
njn25e49d8e72002-09-23 09:36:25 +0000716{
njn1f3a9092002-10-04 09:22:30 +0000717 /* Ignore the permissions, just make it readable. Seems to work... */
nethercote451eae92004-11-02 13:06:32 +0000718 DEBUG("mc_new_mem_startup(%p, %llu, rr=%u, ww=%u, xx=%u)\n",
719 a,(ULong)len,rr,ww,xx);
nethercote8b76fe52004-11-08 19:20:09 +0000720 mc_make_readable(a, len);
njn25e49d8e72002-09-23 09:36:25 +0000721}
722
723static
nethercote451eae92004-11-02 13:06:32 +0000724void mc_new_mem_heap ( Addr a, SizeT len, Bool is_inited )
njn25e49d8e72002-09-23 09:36:25 +0000725{
726 if (is_inited) {
nethercote8b76fe52004-11-08 19:20:09 +0000727 mc_make_readable(a, len);
njn25e49d8e72002-09-23 09:36:25 +0000728 } else {
nethercote8b76fe52004-11-08 19:20:09 +0000729 mc_make_writable(a, len);
njn25e49d8e72002-09-23 09:36:25 +0000730 }
731}
732
733static
nethercote451eae92004-11-02 13:06:32 +0000734void mc_set_perms (Addr a, SizeT len, Bool rr, Bool ww, Bool xx)
njn25e49d8e72002-09-23 09:36:25 +0000735{
nethercote451eae92004-11-02 13:06:32 +0000736 DEBUG("mc_set_perms(%p, %llu, rr=%u ww=%u, xx=%u)\n",
737 a, (ULong)len, rr, ww, xx);
nethercote8b76fe52004-11-08 19:20:09 +0000738 if (rr) mc_make_readable(a, len);
739 else if (ww) mc_make_writable(a, len);
740 else mc_make_noaccess(a, len);
njn25e49d8e72002-09-23 09:36:25 +0000741}
742
njncf45fd42004-11-24 16:30:22 +0000743static
744void mc_post_mem_write(CorePart part, ThreadId tid, Addr a, SizeT len)
745{
746 mc_make_readable(a, len);
747}
njn25e49d8e72002-09-23 09:36:25 +0000748
749/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +0000750/*--- Register event handlers ---*/
751/*------------------------------------------------------------*/
752
njncf45fd42004-11-24 16:30:22 +0000753// When a reg is written, mark the corresponding shadow reg bytes as valid.
754static void mc_post_reg_write(CorePart part, ThreadId tid, OffT offset,
755 SizeT size)
njnd3040452003-05-19 15:04:06 +0000756{
njncf45fd42004-11-24 16:30:22 +0000757 UChar area[size];
758 VG_(memset)(area, VGM_BYTE_VALID, size);
759 VG_(set_shadow_regs_area)( tid, offset, size, area );
njnd3040452003-05-19 15:04:06 +0000760}
761
njncf45fd42004-11-24 16:30:22 +0000762static void mc_post_reg_write_clientcall(ThreadId tid, OffT offset, SizeT size,
763 Addr f)
njnd3040452003-05-19 15:04:06 +0000764{
njncf45fd42004-11-24 16:30:22 +0000765 mc_post_reg_write(/*dummy*/0, tid, offset, size);
njnd3040452003-05-19 15:04:06 +0000766}
767
njncf45fd42004-11-24 16:30:22 +0000768static void mc_pre_reg_read(CorePart part, ThreadId tid, Char* s, OffT offset,
nethercote8b76fe52004-11-08 19:20:09 +0000769 SizeT size)
770{
771 UWord mask;
njncf45fd42004-11-24 16:30:22 +0000772 UWord sh_reg_contents;
nethercote8b76fe52004-11-08 19:20:09 +0000773
774 // XXX: the only one at the moment
njnca82cc02004-11-22 17:18:48 +0000775 tl_assert(Vg_CoreSysCall == part);
nethercote8b76fe52004-11-08 19:20:09 +0000776
777 switch (size) {
778 case 4: mask = 0xffffffff; break;
779 case 2: mask = 0xffff; break;
780 case 1: mask = 0xff; break;
njn67993252004-11-22 18:02:32 +0000781 default: VG_(tool_panic)("Unhandled size in mc_pre_reg_read");
nethercote8b76fe52004-11-08 19:20:09 +0000782 }
783
njncf45fd42004-11-24 16:30:22 +0000784 VG_(get_shadow_regs_area)( tid, offset, size, (UChar*)&sh_reg_contents );
785 if ( VGM_WORD_VALID != (mask & sh_reg_contents) )
nethercote8b76fe52004-11-08 19:20:09 +0000786 MAC_(record_param_error) ( tid, 0, /*isReg*/True, /*isUnaddr*/False, s );
787}
njnd3040452003-05-19 15:04:06 +0000788
789/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +0000790/*--- Functions called directly from generated code. ---*/
791/*------------------------------------------------------------*/
792
793static __inline__ UInt rotateRight16 ( UInt x )
794{
795 /* Amazingly, gcc turns this into a single rotate insn. */
796 return (x >> 16) | (x << 16);
797}
798
799
800static __inline__ UInt shiftRight16 ( UInt x )
801{
802 return x >> 16;
803}
804
805
sewardj95448072004-11-22 20:19:51 +0000806/* Read/write 1/2/4/8 sized V bytes, and emit an address error if
njn25e49d8e72002-09-23 09:36:25 +0000807 needed. */
808
sewardj95448072004-11-22 20:19:51 +0000809/* MC_(helperc_{LD,ST}V{1,2,4,8}) handle the common case fast.
njn25e49d8e72002-09-23 09:36:25 +0000810 Under all other circumstances, it defers to the relevant _SLOWLY
811 function, which can handle all situations.
812*/
sewardj95448072004-11-22 20:19:51 +0000813
814/* ------------------------ Size = 8 ------------------------ */
815
816REGPARM(1)
817ULong MC_(helperc_LOADV8) ( Addr a )
818{
819# ifdef VG_DEBUG_MEMORY
820 return mc_rd_V8_SLOWLY(a);
821# else
njnedfa0f62004-11-30 18:08:05 +0000822 if (IS_4_ALIGNED(a)) {
sewardj95448072004-11-22 20:19:51 +0000823 UInt sec_no = shiftRight16(a) & 0xFFFF;
824 SecMap* sm = primary_map[sec_no];
825 UInt a_off = (a & 0xFFFF) >> 3;
826 UChar abits = sm->abits[a_off];
827 if (abits == VGM_BYTE_VALID) {
828 /* a is 8-aligned, mapped, and addressible. */
829 UInt v_off = a & 0xFFFF;
830 /* LITTLE-ENDIAN */
831 UInt vLo = ((UInt*)(sm->vbyte))[ (v_off >> 2) ];
832 UInt vHi = ((UInt*)(sm->vbyte))[ (v_off >> 2) + 1 ];
833 return ( ((ULong)vHi) << 32 ) | ((ULong)vLo);
834 } else {
835 return mc_rd_V8_SLOWLY(a);
836 }
837 }
838 else
njnedfa0f62004-11-30 18:08:05 +0000839 if (IS_4_ALIGNED(a)) {
sewardj95448072004-11-22 20:19:51 +0000840 /* LITTLE-ENDIAN */
841 UInt vLo = MC_(helperc_LOADV4)(a+0);
842 UInt vHi = MC_(helperc_LOADV4)(a+4);
843 return ( ((ULong)vHi) << 32 ) | ((ULong)vLo);
844 }
845 else
846 return mc_rd_V8_SLOWLY(a);
847# endif
848}
849
850REGPARM(1)
851void MC_(helperc_STOREV8) ( Addr a, ULong vbytes )
852{
853# ifdef VG_DEBUG_MEMORY
854 mc_wr_V8_SLOWLY(a, vbytes);
855# else
njnedfa0f62004-11-30 18:08:05 +0000856 if (IS_4_ALIGNED(a)) {
sewardj95448072004-11-22 20:19:51 +0000857 UInt sec_no = shiftRight16(a) & 0xFFFF;
858 SecMap* sm = primary_map[sec_no];
859 UInt a_off = (a & 0xFFFF) >> 3;
860 UChar abits = sm->abits[a_off];
861 if (abits == VGM_BYTE_VALID) {
862 /* a is 8-aligned, mapped, and addressible. */
863 UInt v_off = a & 0xFFFF;
864 UInt vHi = (UInt)(vbytes >> 32);
865 UInt vLo = (UInt)vbytes;
866 /* LITTLE-ENDIAN */
867 ((UInt*)(sm->vbyte))[ (v_off >> 2) ] = vLo;
868 ((UInt*)(sm->vbyte))[ (v_off >> 2) + 1 ] = vHi;
869 } else {
870 mc_wr_V8_SLOWLY(a, vbytes);
871 }
872 return;
873 }
874 else
njnedfa0f62004-11-30 18:08:05 +0000875 if (IS_4_ALIGNED(a)) {
sewardj95448072004-11-22 20:19:51 +0000876 UInt vHi = (UInt)(vbytes >> 32);
877 UInt vLo = (UInt)vbytes;
878 /* LITTLE-ENDIAN */
879 MC_(helperc_STOREV4)(a+0, vLo);
880 MC_(helperc_STOREV4)(a+4, vHi);
881 return;
882 }
883 else
884 mc_wr_V8_SLOWLY(a, vbytes);
885# endif
886}
887
888/* ------------------------ Size = 4 ------------------------ */
889
nethercoteeec46302004-08-23 15:06:23 +0000890REGPARM(1)
njn5c004e42002-11-18 11:04:50 +0000891UInt MC_(helperc_LOADV4) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +0000892{
893# ifdef VG_DEBUG_MEMORY
njn5c004e42002-11-18 11:04:50 +0000894 return mc_rd_V4_SLOWLY(a);
njn25e49d8e72002-09-23 09:36:25 +0000895# else
896 UInt sec_no = rotateRight16(a) & 0x3FFFF;
897 SecMap* sm = primary_map[sec_no];
898 UInt a_off = (a & 0xFFFF) >> 3;
899 UChar abits = sm->abits[a_off];
900 abits >>= (a & 4);
901 abits &= 15;
902 PROF_EVENT(60);
903 if (abits == VGM_NIBBLE_VALID) {
904 /* Handle common case quickly: a is suitably aligned, is mapped,
905 and is addressible. */
906 UInt v_off = a & 0xFFFF;
907 return ((UInt*)(sm->vbyte))[ v_off >> 2 ];
908 } else {
909 /* Slow but general case. */
njn5c004e42002-11-18 11:04:50 +0000910 return mc_rd_V4_SLOWLY(a);
njn25e49d8e72002-09-23 09:36:25 +0000911 }
912# endif
913}
914
nethercoteeec46302004-08-23 15:06:23 +0000915REGPARM(2)
njn5c004e42002-11-18 11:04:50 +0000916void MC_(helperc_STOREV4) ( Addr a, UInt vbytes )
njn25e49d8e72002-09-23 09:36:25 +0000917{
918# ifdef VG_DEBUG_MEMORY
njn5c004e42002-11-18 11:04:50 +0000919 mc_wr_V4_SLOWLY(a, vbytes);
njn25e49d8e72002-09-23 09:36:25 +0000920# else
921 UInt sec_no = rotateRight16(a) & 0x3FFFF;
922 SecMap* sm = primary_map[sec_no];
923 UInt a_off = (a & 0xFFFF) >> 3;
924 UChar abits = sm->abits[a_off];
925 abits >>= (a & 4);
926 abits &= 15;
927 PROF_EVENT(61);
928 if (abits == VGM_NIBBLE_VALID) {
929 /* Handle common case quickly: a is suitably aligned, is mapped,
930 and is addressible. */
931 UInt v_off = a & 0xFFFF;
932 ((UInt*)(sm->vbyte))[ v_off >> 2 ] = vbytes;
933 } else {
934 /* Slow but general case. */
njn5c004e42002-11-18 11:04:50 +0000935 mc_wr_V4_SLOWLY(a, vbytes);
njn25e49d8e72002-09-23 09:36:25 +0000936 }
937# endif
938}
939
sewardj95448072004-11-22 20:19:51 +0000940/* ------------------------ Size = 2 ------------------------ */
941
nethercoteeec46302004-08-23 15:06:23 +0000942REGPARM(1)
njn5c004e42002-11-18 11:04:50 +0000943UInt MC_(helperc_LOADV2) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +0000944{
945# ifdef VG_DEBUG_MEMORY
njn5c004e42002-11-18 11:04:50 +0000946 return mc_rd_V2_SLOWLY(a);
njn25e49d8e72002-09-23 09:36:25 +0000947# else
948 UInt sec_no = rotateRight16(a) & 0x1FFFF;
949 SecMap* sm = primary_map[sec_no];
950 UInt a_off = (a & 0xFFFF) >> 3;
951 PROF_EVENT(62);
952 if (sm->abits[a_off] == VGM_BYTE_VALID) {
953 /* Handle common case quickly. */
954 UInt v_off = a & 0xFFFF;
955 return 0xFFFF0000
956 |
957 (UInt)( ((UShort*)(sm->vbyte))[ v_off >> 1 ] );
958 } else {
959 /* Slow but general case. */
njn5c004e42002-11-18 11:04:50 +0000960 return mc_rd_V2_SLOWLY(a);
njn25e49d8e72002-09-23 09:36:25 +0000961 }
962# endif
963}
964
nethercoteeec46302004-08-23 15:06:23 +0000965REGPARM(2)
njn5c004e42002-11-18 11:04:50 +0000966void MC_(helperc_STOREV2) ( Addr a, UInt vbytes )
njn25e49d8e72002-09-23 09:36:25 +0000967{
968# ifdef VG_DEBUG_MEMORY
njn5c004e42002-11-18 11:04:50 +0000969 mc_wr_V2_SLOWLY(a, vbytes);
njn25e49d8e72002-09-23 09:36:25 +0000970# else
971 UInt sec_no = rotateRight16(a) & 0x1FFFF;
972 SecMap* sm = primary_map[sec_no];
973 UInt a_off = (a & 0xFFFF) >> 3;
974 PROF_EVENT(63);
975 if (sm->abits[a_off] == VGM_BYTE_VALID) {
976 /* Handle common case quickly. */
977 UInt v_off = a & 0xFFFF;
978 ((UShort*)(sm->vbyte))[ v_off >> 1 ] = vbytes & 0x0000FFFF;
979 } else {
980 /* Slow but general case. */
njn5c004e42002-11-18 11:04:50 +0000981 mc_wr_V2_SLOWLY(a, vbytes);
njn25e49d8e72002-09-23 09:36:25 +0000982 }
983# endif
984}
985
sewardj95448072004-11-22 20:19:51 +0000986/* ------------------------ Size = 1 ------------------------ */
987
nethercoteeec46302004-08-23 15:06:23 +0000988REGPARM(1)
njn5c004e42002-11-18 11:04:50 +0000989UInt MC_(helperc_LOADV1) ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +0000990{
991# ifdef VG_DEBUG_MEMORY
njn5c004e42002-11-18 11:04:50 +0000992 return mc_rd_V1_SLOWLY(a);
njn25e49d8e72002-09-23 09:36:25 +0000993# else
994 UInt sec_no = shiftRight16(a);
995 SecMap* sm = primary_map[sec_no];
996 UInt a_off = (a & 0xFFFF) >> 3;
997 PROF_EVENT(64);
998 if (sm->abits[a_off] == VGM_BYTE_VALID) {
999 /* Handle common case quickly. */
1000 UInt v_off = a & 0xFFFF;
1001 return 0xFFFFFF00
1002 |
1003 (UInt)( ((UChar*)(sm->vbyte))[ v_off ] );
1004 } else {
1005 /* Slow but general case. */
njn5c004e42002-11-18 11:04:50 +00001006 return mc_rd_V1_SLOWLY(a);
njn25e49d8e72002-09-23 09:36:25 +00001007 }
1008# endif
1009}
1010
nethercoteeec46302004-08-23 15:06:23 +00001011REGPARM(2)
njn5c004e42002-11-18 11:04:50 +00001012void MC_(helperc_STOREV1) ( Addr a, UInt vbytes )
njn25e49d8e72002-09-23 09:36:25 +00001013{
1014# ifdef VG_DEBUG_MEMORY
njn5c004e42002-11-18 11:04:50 +00001015 mc_wr_V1_SLOWLY(a, vbytes);
njn25e49d8e72002-09-23 09:36:25 +00001016# else
1017 UInt sec_no = shiftRight16(a);
1018 SecMap* sm = primary_map[sec_no];
1019 UInt a_off = (a & 0xFFFF) >> 3;
1020 PROF_EVENT(65);
1021 if (sm->abits[a_off] == VGM_BYTE_VALID) {
1022 /* Handle common case quickly. */
1023 UInt v_off = a & 0xFFFF;
1024 ((UChar*)(sm->vbyte))[ v_off ] = vbytes & 0x000000FF;
1025 } else {
1026 /* Slow but general case. */
njn5c004e42002-11-18 11:04:50 +00001027 mc_wr_V1_SLOWLY(a, vbytes);
njn25e49d8e72002-09-23 09:36:25 +00001028 }
1029# endif
1030}
1031
1032
1033/*------------------------------------------------------------*/
1034/*--- Fallback functions to handle cases that the above ---*/
sewardj95448072004-11-22 20:19:51 +00001035/*--- VG_(helperc_{LD,ST}V{1,2,4,8}) can't manage. ---*/
njn25e49d8e72002-09-23 09:36:25 +00001036/*------------------------------------------------------------*/
1037
sewardj95448072004-11-22 20:19:51 +00001038/* ------------------------ Size = 8 ------------------------ */
1039
1040static ULong mc_rd_V8_SLOWLY ( Addr a )
1041{
1042 Bool a0ok, a1ok, a2ok, a3ok, a4ok, a5ok, a6ok, a7ok;
1043 UInt vb0, vb1, vb2, vb3, vb4, vb5, vb6, vb7;
1044
1045 PROF_EVENT(70);
1046
1047 /* First establish independently the addressibility of the 4 bytes
1048 involved. */
1049 a0ok = get_abit(a+0) == VGM_BIT_VALID;
1050 a1ok = get_abit(a+1) == VGM_BIT_VALID;
1051 a2ok = get_abit(a+2) == VGM_BIT_VALID;
1052 a3ok = get_abit(a+3) == VGM_BIT_VALID;
1053 a4ok = get_abit(a+4) == VGM_BIT_VALID;
1054 a5ok = get_abit(a+5) == VGM_BIT_VALID;
1055 a6ok = get_abit(a+6) == VGM_BIT_VALID;
1056 a7ok = get_abit(a+7) == VGM_BIT_VALID;
1057
1058 /* Also get the validity bytes for the address. */
1059 vb0 = (UInt)get_vbyte(a+0);
1060 vb1 = (UInt)get_vbyte(a+1);
1061 vb2 = (UInt)get_vbyte(a+2);
1062 vb3 = (UInt)get_vbyte(a+3);
1063 vb4 = (UInt)get_vbyte(a+4);
1064 vb5 = (UInt)get_vbyte(a+5);
1065 vb6 = (UInt)get_vbyte(a+6);
1066 vb7 = (UInt)get_vbyte(a+7);
1067
1068 /* Now distinguish 3 cases */
1069
1070 /* Case 1: the address is completely valid, so:
1071 - no addressing error
1072 - return V bytes as read from memory
1073 */
1074 if (a0ok && a1ok && a2ok && a3ok && a4ok && a5ok && a6ok && a7ok) {
1075 ULong vw = VGM_WORD64_INVALID;
1076 vw <<= 8; vw |= vb7;
1077 vw <<= 8; vw |= vb6;
1078 vw <<= 8; vw |= vb5;
1079 vw <<= 8; vw |= vb4;
1080 vw <<= 8; vw |= vb3;
1081 vw <<= 8; vw |= vb2;
1082 vw <<= 8; vw |= vb1;
1083 vw <<= 8; vw |= vb0;
1084 return vw;
1085 }
1086
1087 /* Case 2: the address is completely invalid.
1088 - emit addressing error
1089 - return V word indicating validity.
1090 This sounds strange, but if we make loads from invalid addresses
1091 give invalid data, we also risk producing a number of confusing
1092 undefined-value errors later, which confuses the fact that the
1093 error arose in the first place from an invalid address.
1094 */
1095 /* VG_(printf)("%p (%d %d %d %d)\n", a, a0ok, a1ok, a2ok, a3ok); */
1096 if (!MAC_(clo_partial_loads_ok)
1097 || ((a & 7) != 0)
1098 || (!a0ok && !a1ok && !a2ok && !a3ok && !a4ok && !a5ok && !a6ok && !a7ok)) {
1099 MAC_(record_address_error)( VG_(get_current_tid)(), a, 8, False );
1100 return VGM_WORD64_VALID;
1101 }
1102
1103 /* Case 3: the address is partially valid.
1104 - no addressing error
1105 - returned V word is invalid where the address is invalid,
1106 and contains V bytes from memory otherwise.
1107 Case 3 is only allowed if MC_(clo_partial_loads_ok) is True
1108 (which is the default), and the address is 4-aligned.
1109 If not, Case 2 will have applied.
1110 */
1111 tl_assert(MAC_(clo_partial_loads_ok));
1112 {
1113 ULong vw = VGM_WORD64_INVALID;
1114 vw <<= 8; vw |= (a7ok ? vb7 : VGM_BYTE_INVALID);
1115 vw <<= 8; vw |= (a6ok ? vb6 : VGM_BYTE_INVALID);
1116 vw <<= 8; vw |= (a5ok ? vb5 : VGM_BYTE_INVALID);
1117 vw <<= 8; vw |= (a4ok ? vb4 : VGM_BYTE_INVALID);
1118 vw <<= 8; vw |= (a3ok ? vb3 : VGM_BYTE_INVALID);
1119 vw <<= 8; vw |= (a2ok ? vb2 : VGM_BYTE_INVALID);
1120 vw <<= 8; vw |= (a1ok ? vb1 : VGM_BYTE_INVALID);
1121 vw <<= 8; vw |= (a0ok ? vb0 : VGM_BYTE_INVALID);
1122 return vw;
1123 }
1124}
1125
1126static void mc_wr_V8_SLOWLY ( Addr a, ULong vbytes )
1127{
1128 /* Check the address for validity. */
1129 Bool aerr = False;
1130 PROF_EVENT(71);
1131
1132 if (get_abit(a+0) != VGM_BIT_VALID) aerr = True;
1133 if (get_abit(a+1) != VGM_BIT_VALID) aerr = True;
1134 if (get_abit(a+2) != VGM_BIT_VALID) aerr = True;
1135 if (get_abit(a+3) != VGM_BIT_VALID) aerr = True;
1136 if (get_abit(a+4) != VGM_BIT_VALID) aerr = True;
1137 if (get_abit(a+5) != VGM_BIT_VALID) aerr = True;
1138 if (get_abit(a+6) != VGM_BIT_VALID) aerr = True;
1139 if (get_abit(a+7) != VGM_BIT_VALID) aerr = True;
1140
1141 /* Store the V bytes, remembering to do it little-endian-ly. */
1142 set_vbyte( a+0, vbytes & 0x000000FF ); vbytes >>= 8;
1143 set_vbyte( a+1, vbytes & 0x000000FF ); vbytes >>= 8;
1144 set_vbyte( a+2, vbytes & 0x000000FF ); vbytes >>= 8;
1145 set_vbyte( a+3, vbytes & 0x000000FF ); vbytes >>= 8;
1146 set_vbyte( a+4, vbytes & 0x000000FF ); vbytes >>= 8;
1147 set_vbyte( a+5, vbytes & 0x000000FF ); vbytes >>= 8;
1148 set_vbyte( a+6, vbytes & 0x000000FF ); vbytes >>= 8;
1149 set_vbyte( a+7, vbytes & 0x000000FF );
1150
1151 /* If an address error has happened, report it. */
1152 if (aerr)
1153 MAC_(record_address_error)( VG_(get_current_tid)(), a, 8, True );
1154}
1155
1156/* ------------------------ Size = 4 ------------------------ */
1157
njn5c004e42002-11-18 11:04:50 +00001158static UInt mc_rd_V4_SLOWLY ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00001159{
1160 Bool a0ok, a1ok, a2ok, a3ok;
1161 UInt vb0, vb1, vb2, vb3;
1162
1163 PROF_EVENT(70);
1164
1165 /* First establish independently the addressibility of the 4 bytes
1166 involved. */
1167 a0ok = get_abit(a+0) == VGM_BIT_VALID;
1168 a1ok = get_abit(a+1) == VGM_BIT_VALID;
1169 a2ok = get_abit(a+2) == VGM_BIT_VALID;
1170 a3ok = get_abit(a+3) == VGM_BIT_VALID;
1171
1172 /* Also get the validity bytes for the address. */
1173 vb0 = (UInt)get_vbyte(a+0);
1174 vb1 = (UInt)get_vbyte(a+1);
1175 vb2 = (UInt)get_vbyte(a+2);
1176 vb3 = (UInt)get_vbyte(a+3);
1177
1178 /* Now distinguish 3 cases */
1179
1180 /* Case 1: the address is completely valid, so:
1181 - no addressing error
1182 - return V bytes as read from memory
1183 */
1184 if (a0ok && a1ok && a2ok && a3ok) {
1185 UInt vw = VGM_WORD_INVALID;
1186 vw <<= 8; vw |= vb3;
1187 vw <<= 8; vw |= vb2;
1188 vw <<= 8; vw |= vb1;
1189 vw <<= 8; vw |= vb0;
1190 return vw;
1191 }
1192
1193 /* Case 2: the address is completely invalid.
1194 - emit addressing error
1195 - return V word indicating validity.
1196 This sounds strange, but if we make loads from invalid addresses
1197 give invalid data, we also risk producing a number of confusing
1198 undefined-value errors later, which confuses the fact that the
1199 error arose in the first place from an invalid address.
1200 */
1201 /* VG_(printf)("%p (%d %d %d %d)\n", a, a0ok, a1ok, a2ok, a3ok); */
njn43c799e2003-04-08 00:08:52 +00001202 if (!MAC_(clo_partial_loads_ok)
njn25e49d8e72002-09-23 09:36:25 +00001203 || ((a & 3) != 0)
1204 || (!a0ok && !a1ok && !a2ok && !a3ok)) {
njn72718642003-07-24 08:45:32 +00001205 MAC_(record_address_error)( VG_(get_current_tid)(), a, 4, False );
njn25e49d8e72002-09-23 09:36:25 +00001206 return (VGM_BYTE_VALID << 24) | (VGM_BYTE_VALID << 16)
1207 | (VGM_BYTE_VALID << 8) | VGM_BYTE_VALID;
1208 }
1209
1210 /* Case 3: the address is partially valid.
1211 - no addressing error
1212 - returned V word is invalid where the address is invalid,
1213 and contains V bytes from memory otherwise.
njn5c004e42002-11-18 11:04:50 +00001214 Case 3 is only allowed if MC_(clo_partial_loads_ok) is True
njn25e49d8e72002-09-23 09:36:25 +00001215 (which is the default), and the address is 4-aligned.
1216 If not, Case 2 will have applied.
1217 */
njnca82cc02004-11-22 17:18:48 +00001218 tl_assert(MAC_(clo_partial_loads_ok));
njn25e49d8e72002-09-23 09:36:25 +00001219 {
1220 UInt vw = VGM_WORD_INVALID;
1221 vw <<= 8; vw |= (a3ok ? vb3 : VGM_BYTE_INVALID);
1222 vw <<= 8; vw |= (a2ok ? vb2 : VGM_BYTE_INVALID);
1223 vw <<= 8; vw |= (a1ok ? vb1 : VGM_BYTE_INVALID);
1224 vw <<= 8; vw |= (a0ok ? vb0 : VGM_BYTE_INVALID);
1225 return vw;
1226 }
1227}
1228
njn5c004e42002-11-18 11:04:50 +00001229static void mc_wr_V4_SLOWLY ( Addr a, UInt vbytes )
njn25e49d8e72002-09-23 09:36:25 +00001230{
1231 /* Check the address for validity. */
1232 Bool aerr = False;
1233 PROF_EVENT(71);
1234
1235 if (get_abit(a+0) != VGM_BIT_VALID) aerr = True;
1236 if (get_abit(a+1) != VGM_BIT_VALID) aerr = True;
1237 if (get_abit(a+2) != VGM_BIT_VALID) aerr = True;
1238 if (get_abit(a+3) != VGM_BIT_VALID) aerr = True;
1239
1240 /* Store the V bytes, remembering to do it little-endian-ly. */
1241 set_vbyte( a+0, vbytes & 0x000000FF ); vbytes >>= 8;
1242 set_vbyte( a+1, vbytes & 0x000000FF ); vbytes >>= 8;
1243 set_vbyte( a+2, vbytes & 0x000000FF ); vbytes >>= 8;
1244 set_vbyte( a+3, vbytes & 0x000000FF );
1245
1246 /* If an address error has happened, report it. */
1247 if (aerr)
njn72718642003-07-24 08:45:32 +00001248 MAC_(record_address_error)( VG_(get_current_tid)(), a, 4, True );
njn25e49d8e72002-09-23 09:36:25 +00001249}
1250
sewardj95448072004-11-22 20:19:51 +00001251/* ------------------------ Size = 2 ------------------------ */
1252
njn5c004e42002-11-18 11:04:50 +00001253static UInt mc_rd_V2_SLOWLY ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00001254{
1255 /* Check the address for validity. */
1256 UInt vw = VGM_WORD_INVALID;
1257 Bool aerr = False;
1258 PROF_EVENT(72);
1259
1260 if (get_abit(a+0) != VGM_BIT_VALID) aerr = True;
1261 if (get_abit(a+1) != VGM_BIT_VALID) aerr = True;
1262
1263 /* Fetch the V bytes, remembering to do it little-endian-ly. */
1264 vw <<= 8; vw |= (UInt)get_vbyte(a+1);
1265 vw <<= 8; vw |= (UInt)get_vbyte(a+0);
1266
1267 /* If an address error has happened, report it. */
1268 if (aerr) {
njn72718642003-07-24 08:45:32 +00001269 MAC_(record_address_error)( VG_(get_current_tid)(), a, 2, False );
njn25e49d8e72002-09-23 09:36:25 +00001270 vw = (VGM_BYTE_INVALID << 24) | (VGM_BYTE_INVALID << 16)
1271 | (VGM_BYTE_VALID << 8) | (VGM_BYTE_VALID);
1272 }
1273 return vw;
1274}
1275
njn5c004e42002-11-18 11:04:50 +00001276static void mc_wr_V2_SLOWLY ( Addr a, UInt vbytes )
njn25e49d8e72002-09-23 09:36:25 +00001277{
1278 /* Check the address for validity. */
1279 Bool aerr = False;
1280 PROF_EVENT(73);
1281
1282 if (get_abit(a+0) != VGM_BIT_VALID) aerr = True;
1283 if (get_abit(a+1) != VGM_BIT_VALID) aerr = True;
1284
1285 /* Store the V bytes, remembering to do it little-endian-ly. */
1286 set_vbyte( a+0, vbytes & 0x000000FF ); vbytes >>= 8;
1287 set_vbyte( a+1, vbytes & 0x000000FF );
1288
1289 /* If an address error has happened, report it. */
1290 if (aerr)
njn72718642003-07-24 08:45:32 +00001291 MAC_(record_address_error)( VG_(get_current_tid)(), a, 2, True );
njn25e49d8e72002-09-23 09:36:25 +00001292}
1293
sewardj95448072004-11-22 20:19:51 +00001294/* ------------------------ Size = 1 ------------------------ */
1295
njn5c004e42002-11-18 11:04:50 +00001296static UInt mc_rd_V1_SLOWLY ( Addr a )
njn25e49d8e72002-09-23 09:36:25 +00001297{
1298 /* Check the address for validity. */
1299 UInt vw = VGM_WORD_INVALID;
1300 Bool aerr = False;
1301 PROF_EVENT(74);
1302
1303 if (get_abit(a+0) != VGM_BIT_VALID) aerr = True;
1304
1305 /* Fetch the V byte. */
1306 vw <<= 8; vw |= (UInt)get_vbyte(a+0);
1307
1308 /* If an address error has happened, report it. */
1309 if (aerr) {
njn72718642003-07-24 08:45:32 +00001310 MAC_(record_address_error)( VG_(get_current_tid)(), a, 1, False );
njn25e49d8e72002-09-23 09:36:25 +00001311 vw = (VGM_BYTE_INVALID << 24) | (VGM_BYTE_INVALID << 16)
1312 | (VGM_BYTE_INVALID << 8) | (VGM_BYTE_VALID);
1313 }
1314 return vw;
1315}
1316
njn5c004e42002-11-18 11:04:50 +00001317static void mc_wr_V1_SLOWLY ( Addr a, UInt vbytes )
njn25e49d8e72002-09-23 09:36:25 +00001318{
1319 /* Check the address for validity. */
1320 Bool aerr = False;
1321 PROF_EVENT(75);
1322 if (get_abit(a+0) != VGM_BIT_VALID) aerr = True;
1323
1324 /* Store the V bytes, remembering to do it little-endian-ly. */
1325 set_vbyte( a+0, vbytes & 0x000000FF );
1326
1327 /* If an address error has happened, report it. */
1328 if (aerr)
njn72718642003-07-24 08:45:32 +00001329 MAC_(record_address_error)( VG_(get_current_tid)(), a, 1, True );
njn25e49d8e72002-09-23 09:36:25 +00001330}
1331
1332
1333/* ---------------------------------------------------------------------
1334 Called from generated code, or from the assembly helpers.
1335 Handlers for value check failures.
1336 ------------------------------------------------------------------ */
1337
njn5c004e42002-11-18 11:04:50 +00001338void MC_(helperc_value_check0_fail) ( void )
njn25e49d8e72002-09-23 09:36:25 +00001339{
njn72718642003-07-24 08:45:32 +00001340 MC_(record_value_error) ( VG_(get_current_tid)(), 0 );
njn25e49d8e72002-09-23 09:36:25 +00001341}
1342
njn5c004e42002-11-18 11:04:50 +00001343void MC_(helperc_value_check1_fail) ( void )
njn25e49d8e72002-09-23 09:36:25 +00001344{
njn72718642003-07-24 08:45:32 +00001345 MC_(record_value_error) ( VG_(get_current_tid)(), 1 );
njn25e49d8e72002-09-23 09:36:25 +00001346}
1347
njn5c004e42002-11-18 11:04:50 +00001348void MC_(helperc_value_check2_fail) ( void )
njn25e49d8e72002-09-23 09:36:25 +00001349{
njn72718642003-07-24 08:45:32 +00001350 MC_(record_value_error) ( VG_(get_current_tid)(), 2 );
njn25e49d8e72002-09-23 09:36:25 +00001351}
1352
njn5c004e42002-11-18 11:04:50 +00001353void MC_(helperc_value_check4_fail) ( void )
njn25e49d8e72002-09-23 09:36:25 +00001354{
njn72718642003-07-24 08:45:32 +00001355 MC_(record_value_error) ( VG_(get_current_tid)(), 4 );
njn25e49d8e72002-09-23 09:36:25 +00001356}
1357
sewardj95448072004-11-22 20:19:51 +00001358REGPARM(1) void MC_(helperc_complain_undef) ( HWord sz )
1359{
1360 MC_(record_value_error) ( VG_(get_current_tid)(), (Int)sz );
1361}
1362
njn25e49d8e72002-09-23 09:36:25 +00001363
njn25e49d8e72002-09-23 09:36:25 +00001364/*------------------------------------------------------------*/
sewardjee070842003-07-05 17:53:55 +00001365/*--- Metadata get/set functions, for client requests. ---*/
1366/*------------------------------------------------------------*/
1367
1368/* Copy Vbits for src into vbits. Returns: 1 == OK, 2 == alignment
1369 error, 3 == addressing error. */
nethercote8b76fe52004-11-08 19:20:09 +00001370static Int mc_get_or_set_vbits_for_client (
njn72718642003-07-24 08:45:32 +00001371 ThreadId tid,
sewardjee070842003-07-05 17:53:55 +00001372 Addr dataV,
1373 Addr vbitsV,
nethercote451eae92004-11-02 13:06:32 +00001374 SizeT size,
sewardjee070842003-07-05 17:53:55 +00001375 Bool setting /* True <=> set vbits, False <=> get vbits */
1376)
1377{
1378 Bool addressibleD = True;
1379 Bool addressibleV = True;
1380 UInt* data = (UInt*)dataV;
1381 UInt* vbits = (UInt*)vbitsV;
nethercote451eae92004-11-02 13:06:32 +00001382 SizeT szW = size / 4; /* sigh */
1383 SizeT i;
sewardjaf48a602003-07-06 00:54:47 +00001384 UInt* dataP = NULL; /* bogus init to keep gcc happy */
1385 UInt* vbitsP = NULL; /* ditto */
sewardjee070842003-07-05 17:53:55 +00001386
1387 /* Check alignment of args. */
njnedfa0f62004-11-30 18:08:05 +00001388 if (!(IS_4_ALIGNED(data) && IS_4_ALIGNED(vbits)))
sewardjee070842003-07-05 17:53:55 +00001389 return 2;
1390 if ((size & 3) != 0)
1391 return 2;
1392
1393 /* Check that arrays are addressible. */
1394 for (i = 0; i < szW; i++) {
sewardjaf48a602003-07-06 00:54:47 +00001395 dataP = &data[i];
1396 vbitsP = &vbits[i];
sewardjee070842003-07-05 17:53:55 +00001397 if (get_abits4_ALIGNED((Addr)dataP) != VGM_NIBBLE_VALID) {
1398 addressibleD = False;
1399 break;
1400 }
1401 if (get_abits4_ALIGNED((Addr)vbitsP) != VGM_NIBBLE_VALID) {
1402 addressibleV = False;
1403 break;
1404 }
1405 }
1406 if (!addressibleD) {
njn72718642003-07-24 08:45:32 +00001407 MAC_(record_address_error)( tid, (Addr)dataP, 4,
sewardjee070842003-07-05 17:53:55 +00001408 setting ? True : False );
1409 return 3;
1410 }
1411 if (!addressibleV) {
njn72718642003-07-24 08:45:32 +00001412 MAC_(record_address_error)( tid, (Addr)vbitsP, 4,
sewardjee070842003-07-05 17:53:55 +00001413 setting ? False : True );
1414 return 3;
1415 }
1416
1417 /* Do the copy */
1418 if (setting) {
1419 /* setting */
1420 for (i = 0; i < szW; i++) {
1421 if (get_vbytes4_ALIGNED( (Addr)&vbits[i] ) != VGM_WORD_VALID)
njn72718642003-07-24 08:45:32 +00001422 MC_(record_value_error)(tid, 4);
sewardjee070842003-07-05 17:53:55 +00001423 set_vbytes4_ALIGNED( (Addr)&data[i], vbits[i] );
1424 }
1425 } else {
1426 /* getting */
1427 for (i = 0; i < szW; i++) {
1428 vbits[i] = get_vbytes4_ALIGNED( (Addr)&data[i] );
1429 set_vbytes4_ALIGNED( (Addr)&vbits[i], VGM_WORD_VALID );
1430 }
1431 }
1432
1433 return 1;
1434}
1435
1436
1437/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +00001438/*--- Detecting leaked (unreachable) malloc'd blocks. ---*/
1439/*------------------------------------------------------------*/
1440
sewardja4495682002-10-21 07:29:59 +00001441/* For the memory leak detector, say whether an entire 64k chunk of
1442 address space is possibly in use, or not. If in doubt return
1443 True.
njn25e49d8e72002-09-23 09:36:25 +00001444*/
sewardja4495682002-10-21 07:29:59 +00001445static
1446Bool mc_is_valid_64k_chunk ( UInt chunk_number )
njn25e49d8e72002-09-23 09:36:25 +00001447{
njnca82cc02004-11-22 17:18:48 +00001448 tl_assert(chunk_number >= 0 && chunk_number < 65536);
sewardja4495682002-10-21 07:29:59 +00001449 if (IS_DISTINGUISHED_SM(primary_map[chunk_number])) {
1450 /* Definitely not in use. */
1451 return False;
1452 } else {
1453 return True;
njn25e49d8e72002-09-23 09:36:25 +00001454 }
1455}
1456
1457
sewardja4495682002-10-21 07:29:59 +00001458/* For the memory leak detector, say whether or not a given word
1459 address is to be regarded as valid. */
1460static
1461Bool mc_is_valid_address ( Addr a )
1462{
1463 UInt vbytes;
1464 UChar abits;
njnedfa0f62004-11-30 18:08:05 +00001465 tl_assert(IS_4_ALIGNED(a));
sewardja4495682002-10-21 07:29:59 +00001466 abits = get_abits4_ALIGNED(a);
1467 vbytes = get_vbytes4_ALIGNED(a);
1468 if (abits == VGM_NIBBLE_VALID && vbytes == VGM_WORD_VALID) {
1469 return True;
1470 } else {
1471 return False;
1472 }
1473}
1474
1475
nethercote996901a2004-08-03 13:29:09 +00001476/* Leak detector for this tool. We don't actually do anything, merely
sewardja4495682002-10-21 07:29:59 +00001477 run the generic leak detector with suitable parameters for this
nethercote996901a2004-08-03 13:29:09 +00001478 tool. */
sewardj2a99cf62004-11-24 10:44:19 +00001479static void mc_detect_memory_leaks ( ThreadId tid )
njn25e49d8e72002-09-23 09:36:25 +00001480{
sewardj2a99cf62004-11-24 10:44:19 +00001481 MAC_(do_detect_memory_leaks) (
1482 tid, mc_is_valid_64k_chunk, mc_is_valid_address );
njn25e49d8e72002-09-23 09:36:25 +00001483}
1484
1485
1486/* ---------------------------------------------------------------------
1487 Sanity check machinery (permanently engaged).
1488 ------------------------------------------------------------------ */
1489
njn26f02512004-11-22 18:33:15 +00001490Bool TL_(cheap_sanity_check) ( void )
njn25e49d8e72002-09-23 09:36:25 +00001491{
jseward9800fd32004-01-04 23:08:04 +00001492 /* nothing useful we can rapidly check */
1493 return True;
njn25e49d8e72002-09-23 09:36:25 +00001494}
1495
njn26f02512004-11-22 18:33:15 +00001496Bool TL_(expensive_sanity_check) ( void )
njn25e49d8e72002-09-23 09:36:25 +00001497{
1498 Int i;
1499
1500 /* Make sure nobody changed the distinguished secondary. */
1501 for (i = 0; i < 8192; i++)
1502 if (distinguished_secondary_map.abits[i] != VGM_BYTE_INVALID)
1503 return False;
1504
1505 for (i = 0; i < 65536; i++)
1506 if (distinguished_secondary_map.vbyte[i] != VGM_BYTE_INVALID)
1507 return False;
1508
1509 /* Make sure that the upper 3/4 of the primary map hasn't
1510 been messed with. */
1511 for (i = 65536; i < 262144; i++)
1512 if (primary_map[i] != & distinguished_secondary_map)
1513 return False;
1514
1515 return True;
1516}
1517
njn25e49d8e72002-09-23 09:36:25 +00001518/*------------------------------------------------------------*/
njnd3040452003-05-19 15:04:06 +00001519/*--- Command line args ---*/
njn25e49d8e72002-09-23 09:36:25 +00001520/*------------------------------------------------------------*/
1521
njn43c799e2003-04-08 00:08:52 +00001522Bool MC_(clo_avoid_strlen_errors) = True;
njn43c799e2003-04-08 00:08:52 +00001523
njn26f02512004-11-22 18:33:15 +00001524Bool TL_(process_cmd_line_option)(Char* arg)
njn25e49d8e72002-09-23 09:36:25 +00001525{
nethercote27fec902004-06-16 21:26:32 +00001526 VG_BOOL_CLO("--avoid-strlen-errors", MC_(clo_avoid_strlen_errors))
njn25e49d8e72002-09-23 09:36:25 +00001527 else
njn43c799e2003-04-08 00:08:52 +00001528 return MAC_(process_common_cmd_line_option)(arg);
njn25e49d8e72002-09-23 09:36:25 +00001529
1530 return True;
njn25e49d8e72002-09-23 09:36:25 +00001531}
1532
njn26f02512004-11-22 18:33:15 +00001533void TL_(print_usage)(void)
njn25e49d8e72002-09-23 09:36:25 +00001534{
njn3e884182003-04-15 13:03:23 +00001535 MAC_(print_common_usage)();
1536 VG_(printf)(
1537" --avoid-strlen-errors=no|yes suppress errs from inlined strlen [yes]\n"
1538 );
1539}
1540
njn26f02512004-11-22 18:33:15 +00001541void TL_(print_debug_usage)(void)
njn3e884182003-04-15 13:03:23 +00001542{
1543 MAC_(print_common_debug_usage)();
1544 VG_(printf)(
sewardj8ec2cfc2002-10-13 00:57:26 +00001545" --cleanup=no|yes improve after instrumentation? [yes]\n"
njn3e884182003-04-15 13:03:23 +00001546 );
njn25e49d8e72002-09-23 09:36:25 +00001547}
1548
nethercote8b76fe52004-11-08 19:20:09 +00001549/*------------------------------------------------------------*/
1550/*--- Client requests ---*/
1551/*------------------------------------------------------------*/
1552
1553/* Client block management:
1554
1555 This is managed as an expanding array of client block descriptors.
1556 Indices of live descriptors are issued to the client, so it can ask
1557 to free them later. Therefore we cannot slide live entries down
1558 over dead ones. Instead we must use free/inuse flags and scan for
1559 an empty slot at allocation time. This in turn means allocation is
1560 relatively expensive, so we hope this does not happen too often.
1561*/
1562
1563typedef
1564 enum { CG_NotInUse, CG_NoAccess, CG_Writable, CG_Readable }
1565 CGenBlockKind;
1566
1567typedef
1568 struct {
1569 Addr start;
1570 SizeT size;
1571 ExeContext* where;
1572 CGenBlockKind kind;
1573 }
1574 CGenBlock;
1575
1576/* This subsystem is self-initialising. */
1577static UInt vg_cgb_size = 0;
1578static UInt vg_cgb_used = 0;
1579static CGenBlock* vg_cgbs = NULL;
1580
1581/* Stats for this subsystem. */
1582static UInt vg_cgb_used_MAX = 0; /* Max in use. */
1583static UInt vg_cgb_allocs = 0; /* Number of allocs. */
1584static UInt vg_cgb_discards = 0; /* Number of discards. */
1585static UInt vg_cgb_search = 0; /* Number of searches. */
1586
1587
1588static
1589Int vg_alloc_client_block ( void )
1590{
1591 UInt i, sz_new;
1592 CGenBlock* cgbs_new;
1593
1594 vg_cgb_allocs++;
1595
1596 for (i = 0; i < vg_cgb_used; i++) {
1597 vg_cgb_search++;
1598 if (vg_cgbs[i].kind == CG_NotInUse)
1599 return i;
1600 }
1601
1602 /* Not found. Try to allocate one at the end. */
1603 if (vg_cgb_used < vg_cgb_size) {
1604 vg_cgb_used++;
1605 return vg_cgb_used-1;
1606 }
1607
1608 /* Ok, we have to allocate a new one. */
njnca82cc02004-11-22 17:18:48 +00001609 tl_assert(vg_cgb_used == vg_cgb_size);
nethercote8b76fe52004-11-08 19:20:09 +00001610 sz_new = (vg_cgbs == NULL) ? 10 : (2 * vg_cgb_size);
1611
1612 cgbs_new = VG_(malloc)( sz_new * sizeof(CGenBlock) );
1613 for (i = 0; i < vg_cgb_used; i++)
1614 cgbs_new[i] = vg_cgbs[i];
1615
1616 if (vg_cgbs != NULL)
1617 VG_(free)( vg_cgbs );
1618 vg_cgbs = cgbs_new;
1619
1620 vg_cgb_size = sz_new;
1621 vg_cgb_used++;
1622 if (vg_cgb_used > vg_cgb_used_MAX)
1623 vg_cgb_used_MAX = vg_cgb_used;
1624 return vg_cgb_used-1;
1625}
1626
1627
1628static void show_client_block_stats ( void )
1629{
1630 VG_(message)(Vg_DebugMsg,
1631 "general CBs: %d allocs, %d discards, %d maxinuse, %d search",
1632 vg_cgb_allocs, vg_cgb_discards, vg_cgb_used_MAX, vg_cgb_search
1633 );
1634}
1635
1636static Bool find_addr(VgHashNode* sh_ch, void* ap)
1637{
1638 MAC_Chunk *m = (MAC_Chunk*)sh_ch;
1639 Addr a = *(Addr*)ap;
1640
1641 return VG_(addr_is_in_block)(a, m->data, m->size);
1642}
1643
1644static Bool client_perm_maybe_describe( Addr a, AddrInfo* ai )
1645{
1646 UInt i;
1647 /* VG_(printf)("try to identify %d\n", a); */
1648
1649 /* Perhaps it's a general block ? */
1650 for (i = 0; i < vg_cgb_used; i++) {
1651 if (vg_cgbs[i].kind == CG_NotInUse)
1652 continue;
1653 if (VG_(addr_is_in_block)(a, vg_cgbs[i].start, vg_cgbs[i].size)) {
1654 MAC_Mempool **d, *mp;
1655
1656 /* OK - maybe it's a mempool, too? */
1657 mp = (MAC_Mempool*)VG_(HT_get_node)(MAC_(mempool_list),
1658 (UWord)vg_cgbs[i].start,
1659 (void*)&d);
1660 if(mp != NULL) {
1661 if(mp->chunks != NULL) {
1662 MAC_Chunk *mc;
1663
1664 mc = (MAC_Chunk*)VG_(HT_first_match)(mp->chunks, find_addr, &a);
1665 if(mc != NULL) {
1666 ai->akind = UserG;
1667 ai->blksize = mc->size;
1668 ai->rwoffset = (Int)(a) - (Int)mc->data;
1669 ai->lastchange = mc->where;
1670 return True;
1671 }
1672 }
1673 ai->akind = Mempool;
1674 ai->blksize = vg_cgbs[i].size;
1675 ai->rwoffset = (Int)(a) - (Int)(vg_cgbs[i].start);
1676 ai->lastchange = vg_cgbs[i].where;
1677 return True;
1678 }
1679 ai->akind = UserG;
1680 ai->blksize = vg_cgbs[i].size;
1681 ai->rwoffset = (Int)(a) - (Int)(vg_cgbs[i].start);
1682 ai->lastchange = vg_cgbs[i].where;
1683 return True;
1684 }
1685 }
1686 return False;
1687}
1688
njn26f02512004-11-22 18:33:15 +00001689Bool TL_(handle_client_request) ( ThreadId tid, UWord* arg, UWord* ret )
nethercote8b76fe52004-11-08 19:20:09 +00001690{
1691 Int i;
1692 Bool ok;
1693 Addr bad_addr;
1694
njnfc26ff92004-11-22 19:12:49 +00001695 if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
nethercote8b76fe52004-11-08 19:20:09 +00001696 && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
1697 && VG_USERREQ__FREELIKE_BLOCK != arg[0]
1698 && VG_USERREQ__CREATE_MEMPOOL != arg[0]
1699 && VG_USERREQ__DESTROY_MEMPOOL != arg[0]
1700 && VG_USERREQ__MEMPOOL_ALLOC != arg[0]
1701 && VG_USERREQ__MEMPOOL_FREE != arg[0])
1702 return False;
1703
1704 switch (arg[0]) {
1705 case VG_USERREQ__CHECK_WRITABLE: /* check writable */
1706 ok = mc_check_writable ( arg[1], arg[2], &bad_addr );
1707 if (!ok)
1708 MC_(record_user_error) ( tid, bad_addr, /*isWrite*/True,
1709 /*isUnaddr*/True );
1710 *ret = ok ? (UWord)NULL : bad_addr;
1711 break;
1712
1713 case VG_USERREQ__CHECK_READABLE: { /* check readable */
1714 MC_ReadResult res;
1715 res = mc_check_readable ( arg[1], arg[2], &bad_addr );
1716 if (MC_AddrErr == res)
1717 MC_(record_user_error) ( tid, bad_addr, /*isWrite*/False,
1718 /*isUnaddr*/True );
1719 else if (MC_ValueErr == res)
1720 MC_(record_user_error) ( tid, bad_addr, /*isWrite*/False,
1721 /*isUnaddr*/False );
1722 *ret = ( res==MC_Ok ? (UWord)NULL : bad_addr );
1723 break;
1724 }
1725
1726 case VG_USERREQ__DO_LEAK_CHECK:
sewardj2a99cf62004-11-24 10:44:19 +00001727 mc_detect_memory_leaks(tid);
nethercote8b76fe52004-11-08 19:20:09 +00001728 *ret = 0; /* return value is meaningless */
1729 break;
1730
1731 case VG_USERREQ__MAKE_NOACCESS: /* make no access */
1732 i = vg_alloc_client_block();
1733 /* VG_(printf)("allocated %d %p\n", i, vg_cgbs); */
1734 vg_cgbs[i].kind = CG_NoAccess;
1735 vg_cgbs[i].start = arg[1];
1736 vg_cgbs[i].size = arg[2];
1737 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
1738 mc_make_noaccess ( arg[1], arg[2] );
1739 *ret = i;
1740 break;
1741
1742 case VG_USERREQ__MAKE_WRITABLE: /* make writable */
1743 i = vg_alloc_client_block();
1744 vg_cgbs[i].kind = CG_Writable;
1745 vg_cgbs[i].start = arg[1];
1746 vg_cgbs[i].size = arg[2];
1747 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
1748 mc_make_writable ( arg[1], arg[2] );
1749 *ret = i;
1750 break;
1751
1752 case VG_USERREQ__MAKE_READABLE: /* make readable */
1753 i = vg_alloc_client_block();
1754 vg_cgbs[i].kind = CG_Readable;
1755 vg_cgbs[i].start = arg[1];
1756 vg_cgbs[i].size = arg[2];
1757 vg_cgbs[i].where = VG_(get_ExeContext) ( tid );
1758 mc_make_readable ( arg[1], arg[2] );
1759 *ret = i;
1760 break;
1761
1762 case VG_USERREQ__DISCARD: /* discard */
1763 if (vg_cgbs == NULL
1764 || arg[2] >= vg_cgb_used || vg_cgbs[arg[2]].kind == CG_NotInUse)
1765 return 1;
njnca82cc02004-11-22 17:18:48 +00001766 tl_assert(arg[2] >= 0 && arg[2] < vg_cgb_used);
nethercote8b76fe52004-11-08 19:20:09 +00001767 vg_cgbs[arg[2]].kind = CG_NotInUse;
1768 vg_cgb_discards++;
1769 *ret = 0;
1770 break;
1771
1772 case VG_USERREQ__GET_VBITS:
1773 /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
1774 error. */
1775 /* VG_(printf)("get_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
1776 *ret = mc_get_or_set_vbits_for_client
1777 ( tid, arg[1], arg[2], arg[3], False /* get them */ );
1778 break;
1779
1780 case VG_USERREQ__SET_VBITS:
1781 /* Returns: 1 == OK, 2 == alignment error, 3 == addressing
1782 error. */
1783 /* VG_(printf)("set_vbits %p %p %d\n", arg[1], arg[2], arg[3] ); */
1784 *ret = mc_get_or_set_vbits_for_client
1785 ( tid, arg[1], arg[2], arg[3], True /* set them */ );
1786 break;
1787
1788 default:
1789 if (MAC_(handle_common_client_requests)(tid, arg, ret )) {
1790 return True;
1791 } else {
1792 VG_(message)(Vg_UserMsg,
1793 "Warning: unknown memcheck client request code %llx",
1794 (ULong)arg[0]);
1795 return False;
1796 }
1797 }
1798 return True;
1799}
njn25e49d8e72002-09-23 09:36:25 +00001800
1801/*------------------------------------------------------------*/
1802/*--- Setup ---*/
1803/*------------------------------------------------------------*/
1804
njn26f02512004-11-22 18:33:15 +00001805void TL_(pre_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +00001806{
njn810086f2002-11-14 12:42:47 +00001807 VG_(details_name) ("Memcheck");
1808 VG_(details_version) (NULL);
nethercote262eedf2003-11-13 17:57:18 +00001809 VG_(details_description) ("a memory error detector");
njn810086f2002-11-14 12:42:47 +00001810 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +00001811 "Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al.");
nethercote421281e2003-11-20 16:20:55 +00001812 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj9ebf9fd2004-11-28 16:56:51 +00001813 VG_(details_avg_translation_sizeB) ( 370 );
njn25e49d8e72002-09-23 09:36:25 +00001814
njn810086f2002-11-14 12:42:47 +00001815 VG_(needs_core_errors) ();
njn95ec8702004-11-22 16:46:13 +00001816 VG_(needs_tool_errors) ();
njn810086f2002-11-14 12:42:47 +00001817 VG_(needs_libc_freeres) ();
njn810086f2002-11-14 12:42:47 +00001818 VG_(needs_command_line_options)();
1819 VG_(needs_client_requests) ();
njn810086f2002-11-14 12:42:47 +00001820 VG_(needs_sanity_checks) ();
fitzhardinge98abfc72003-12-16 02:05:15 +00001821 VG_(needs_shadow_memory) ();
njn25e49d8e72002-09-23 09:36:25 +00001822
njn3e884182003-04-15 13:03:23 +00001823 MAC_( new_mem_heap) = & mc_new_mem_heap;
nethercote8b76fe52004-11-08 19:20:09 +00001824 MAC_( ban_mem_heap) = & mc_make_noaccess;
njn3e884182003-04-15 13:03:23 +00001825 MAC_(copy_mem_heap) = & mc_copy_address_range_state;
nethercote8b76fe52004-11-08 19:20:09 +00001826 MAC_( die_mem_heap) = & mc_make_noaccess;
1827 MAC_(check_noaccess) = & mc_check_noaccess;
njn3e884182003-04-15 13:03:23 +00001828
fitzhardinge98abfc72003-12-16 02:05:15 +00001829 VG_(init_new_mem_startup) ( & mc_new_mem_startup );
nethercote8b76fe52004-11-08 19:20:09 +00001830 VG_(init_new_mem_stack_signal) ( & mc_make_writable );
1831 VG_(init_new_mem_brk) ( & mc_make_writable );
fitzhardinge98abfc72003-12-16 02:05:15 +00001832 VG_(init_new_mem_mmap) ( & mc_set_perms );
njn25e49d8e72002-09-23 09:36:25 +00001833
fitzhardinge98abfc72003-12-16 02:05:15 +00001834 VG_(init_copy_mem_remap) ( & mc_copy_address_range_state );
1835 VG_(init_change_mem_mprotect) ( & mc_set_perms );
njn3e884182003-04-15 13:03:23 +00001836
nethercote8b76fe52004-11-08 19:20:09 +00001837 VG_(init_die_mem_stack_signal) ( & mc_make_noaccess );
1838 VG_(init_die_mem_brk) ( & mc_make_noaccess );
1839 VG_(init_die_mem_munmap) ( & mc_make_noaccess );
njn3e884182003-04-15 13:03:23 +00001840
fitzhardinge98abfc72003-12-16 02:05:15 +00001841 VG_(init_new_mem_stack_4) ( & MAC_(new_mem_stack_4) );
1842 VG_(init_new_mem_stack_8) ( & MAC_(new_mem_stack_8) );
1843 VG_(init_new_mem_stack_12) ( & MAC_(new_mem_stack_12) );
1844 VG_(init_new_mem_stack_16) ( & MAC_(new_mem_stack_16) );
1845 VG_(init_new_mem_stack_32) ( & MAC_(new_mem_stack_32) );
1846 VG_(init_new_mem_stack) ( & MAC_(new_mem_stack) );
njn9b007f62003-04-07 14:40:25 +00001847
fitzhardinge98abfc72003-12-16 02:05:15 +00001848 VG_(init_die_mem_stack_4) ( & MAC_(die_mem_stack_4) );
1849 VG_(init_die_mem_stack_8) ( & MAC_(die_mem_stack_8) );
1850 VG_(init_die_mem_stack_12) ( & MAC_(die_mem_stack_12) );
1851 VG_(init_die_mem_stack_16) ( & MAC_(die_mem_stack_16) );
1852 VG_(init_die_mem_stack_32) ( & MAC_(die_mem_stack_32) );
1853 VG_(init_die_mem_stack) ( & MAC_(die_mem_stack) );
njn9b007f62003-04-07 14:40:25 +00001854
nethercote8b76fe52004-11-08 19:20:09 +00001855 VG_(init_ban_mem_stack) ( & mc_make_noaccess );
njn25e49d8e72002-09-23 09:36:25 +00001856
fitzhardinge98abfc72003-12-16 02:05:15 +00001857 VG_(init_pre_mem_read) ( & mc_check_is_readable );
1858 VG_(init_pre_mem_read_asciiz) ( & mc_check_is_readable_asciiz );
1859 VG_(init_pre_mem_write) ( & mc_check_is_writable );
njncf45fd42004-11-24 16:30:22 +00001860 VG_(init_post_mem_write) ( & mc_post_mem_write );
nethercote8b76fe52004-11-08 19:20:09 +00001861
1862 VG_(init_pre_reg_read) ( & mc_pre_reg_read );
njn25e49d8e72002-09-23 09:36:25 +00001863
njncf45fd42004-11-24 16:30:22 +00001864 VG_(init_post_reg_write) ( & mc_post_reg_write );
fitzhardinge98abfc72003-12-16 02:05:15 +00001865 VG_(init_post_reg_write_clientcall_return) ( & mc_post_reg_write_clientcall );
njnd3040452003-05-19 15:04:06 +00001866
njn25e49d8e72002-09-23 09:36:25 +00001867 VGP_(register_profile_event) ( VgpSetMem, "set-mem-perms" );
1868 VGP_(register_profile_event) ( VgpCheckMem, "check-mem-perms" );
njn9b007f62003-04-07 14:40:25 +00001869 VGP_(register_profile_event) ( VgpESPAdj, "adjust-ESP" );
njnd04b7c62002-10-03 14:05:52 +00001870
njn43c799e2003-04-08 00:08:52 +00001871 /* Additional block description for VG_(describe_addr)() */
nethercote8b76fe52004-11-08 19:20:09 +00001872 MAC_(describe_addr_supp) = client_perm_maybe_describe;
njn43c799e2003-04-08 00:08:52 +00001873
njnd04b7c62002-10-03 14:05:52 +00001874 init_shadow_memory();
njn3e884182003-04-15 13:03:23 +00001875 MAC_(common_pre_clo_init)();
njn5c004e42002-11-18 11:04:50 +00001876}
1877
njn26f02512004-11-22 18:33:15 +00001878void TL_(post_clo_init) ( void )
njn5c004e42002-11-18 11:04:50 +00001879{
1880}
1881
njn26f02512004-11-22 18:33:15 +00001882void TL_(fini) ( Int exitcode )
njn5c004e42002-11-18 11:04:50 +00001883{
nethercote8b76fe52004-11-08 19:20:09 +00001884 MAC_(common_fini)( mc_detect_memory_leaks );
njn3e884182003-04-15 13:03:23 +00001885
njn5c004e42002-11-18 11:04:50 +00001886 if (0) {
1887 VG_(message)(Vg_DebugMsg,
1888 "------ Valgrind's client block stats follow ---------------" );
nethercote8b76fe52004-11-08 19:20:09 +00001889 show_client_block_stats();
njn5c004e42002-11-18 11:04:50 +00001890 }
njn25e49d8e72002-09-23 09:36:25 +00001891}
1892
njn26f02512004-11-22 18:33:15 +00001893VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 9./8)
fitzhardinge98abfc72003-12-16 02:05:15 +00001894
njn25e49d8e72002-09-23 09:36:25 +00001895/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +00001896/*--- end mc_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00001897/*--------------------------------------------------------------------*/