blob: d98f6d3bca15edb648f74ff89d1f85f762caa8fa [file] [log] [blame]
sewardj024598e2008-09-18 14:43:05 +00001
2/*--------------------------------------------------------------------*/
3/*--- Ptrcheck: a pointer-use checker. ---*/
4/*--- This file checks heap accesses. ---*/
5/*--- h_main.c ---*/
6/*--------------------------------------------------------------------*/
7
8/*
9 This file is part of Ptrcheck, a Valgrind tool for checking pointer
10 use in programs.
11
12 Initial version (Annelid):
13
njn9f207462009-03-10 22:02:09 +000014 Copyright (C) 2003-2009 Nicholas Nethercote
sewardj024598e2008-09-18 14:43:05 +000015 njn@valgrind.org
16
17 Valgrind-3.X port:
18
njn9f207462009-03-10 22:02:09 +000019 Copyright (C) 2008-2009 OpenWorks Ltd
sewardj024598e2008-09-18 14:43:05 +000020 info@open-works.co.uk
21
22 This program is free software; you can redistribute it and/or
23 modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2 of the
25 License, or (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful, but
28 WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
35 02111-1307, USA.
36
37 The GNU General Public License is contained in the file COPYING.
38*/
39
40// FIXME: 64-bit cleanness, check the following
41// struct _ISNode.ownerCount is 32-bit
42// struct _ISNode.topLevel is 32-bit
43// or is that not really right now? add assertion checks about
44// the max size of a node
45
46// FIXME: should we shadow %RIP? Maybe not.
47
48// FIXME: shadows of temporaries created in preamble, a la memcheck?
49
50// FIXME: result of add_new_segment is always ignored
51
52// FIXME: the mechanism involving last_seg_added is really ugly.
53// Do something cleaner.
54
55// FIXME: post_reg_write_clientcall: check function pointer comparisons
56// are safe on toc-afflicted platforms
57
58// FIXME: tidy up findShadowTmp
59
60// FIXME: post_reg_write_demux(Vg_CoreSysCall) is redundant w.r.t.
61// the default 'NONPTR' behaviour of post_syscall. post_reg_write_demux
62// is called first, then post_syscall.
63
64// FIXME: check nothing is mapped in the lowest 1M of memory at
65// startup, or quit (to do with nonptr_or_unknown, also sync 1M
66// magic value with PIE default load address in m_ume.c.
67
68// FIXME: consider whether we could paint memory acquired from
69// sys_read etc as NONPTR rather than UNKNOWN.
70
71// XXX: recycle freed segments
72
73//--------------------------------------------------------------
74// Metadata:
75// HeapBlock.id :: Seg (stored as heap shadowchunk; always non-zero)
76// MemLoc.aseg :: Seg (implicitly stored)
77// MemLoc.vseg :: Seg (explicitly stored as the shadow memory)
78// RegLoc.vseg :: Seg (explicitly stored as shadow registers)
79//
80// A Seg is made when new memory is created, eg. with malloc() or mmap().
81// There are two other Segs:
82// - NONPTR: for something that's definitely not a pointer
83// - UNKNOWN: for something that could be a pointer
84// - BOTTOM: used with pointer differences (see below)
85//
86// MemLoc.vseg is done at word granularity. If a pointer is written
87// to memory misaligned, the information about it will be lost -- it's
88// treated as two sub-word writes to two adjacent words. This avoids
89// certain nasty cases that could arise if we tried to track unaligned
90// pointers. Fortunately, misalignment is rare so we don't lose much
91// information this way.
92//
93// MemLoc.aseg is done at byte granularity, and *implicitly* -- ie. not
94// directly accessible like MemLoc.vseg, but only by searching through all
95// the segments. Fortunately, it's mostly checked at LOADs/STOREs; at that
96// point we have a pointer p to the MemLoc m as the other arg of the
97// LOAD/STORE, so we can check to see if the p.vseg's range includes m. If
98// not, it's an error and we have to search through all segments to find out
99// what m.aseg really is. That's still pretty fast though, thanks to the
100// interval skip-list used. With syscalls we must also do the skip-list
101// search, but only on the first and last bytes touched.
102//--------------------------------------------------------------
103
104//--------------------------------------------------------------
105// Assumptions, etc:
106// - see comment at top of SK_(instrument)() for how sub-word ops are
107// handled.
108//
109// - ioctl(), socketcall() (and ipc() will be) assumed to return non-pointers
110//
111// - FPU_W is assumed to never write pointers.
112//
113// - Assuming none of the post_mem_writes create segments worth tracking.
114//
115// - Treating mmap'd segments (all! including code) like heap segments. But
116// their ranges can change, new ones can be created by unmapping parts of
117// old segments, etc. But this nasty behaviour seems to never happen --
118// there are assertions checking it.
119//--------------------------------------------------------------
120
121//--------------------------------------------------------------
122// What I am checking:
123// - Type errors:
124// * ADD, OR, LEA2: error if two pointer inputs.
125// * ADC, SBB: error if one or two pointer inputs.
126// * AND, OR: error if two unequal pointer inputs.
127// * NEG: error if pointer input.
128// * {,i}mul_32_64 if either input is a pointer.
129// * shldl/shrdl, bsf/bsr if any inputs are pointers.
130//
131// - LOAD, STORE:
132// * ptr.vseg must match ptee.aseg.
133// * ptee.aseg must not be a freed segment.
134//
135// - syscalls: for those accessing memory, look at first and last bytes:
136// * check first.aseg == last.aseg
137// * check first.aseg and last.aseg are not freed segments.
138//
139// What I am not checking, that I expected to when I started:
140// - AND, XOR: allowing two pointers to be used if both from the same segment,
141// because "xor %r,%r" is commonly used to zero %r, and "test %r,%r"
142// (which is translated with an AND) is common too.
143//
144// - div_64_32/idiv_64_32 can take pointer inputs for the dividend;
145// division doesn't make sense, but modulo does, and they're done with the
146// same instruction. (Could try to be super-clever and watch the outputs
147// to see if the quotient is used, but not worth it.)
148//
149// - mul_64_32/imul_64_32 can take pointers inputs for one arg or the
150// other, but not both. This is because some programs (eg. Mozilla
151// Firebird) multiply pointers in hash routines.
152//
153// - NEG: can take a pointer. It happens in glibc in a few places. I've
154// seen the code, didn't understand it, but it's done deliberately.
155//
156// What I am not checking/doing, but could, but it would require more
157// instrumentation and/or slow things down a bit:
158// - SUB: when differencing two pointers, result is BOTTOM, ie. "don't
159// check". Could link segments instead, slower but a bit more accurate.
160// Also use BOTTOM when doing (ptr - unknown), which could be a pointer
161// difference with a stack/static pointer.
162//
163// - PUTF: input should be non-pointer
164//
165// - arithmetic error messages: eg. for adding two pointers, just giving the
166// segments, not the actual pointers.
167//
168// What I am not checking, and would be difficult:
169// - mmap(...MAP_FIXED...) is not handled specially. It might be used in
170// ways that fool Ptrcheck into giving false positives.
171//
172// - syscalls: for those accessing memory, not checking that the asegs of the
173// accessed words match the vseg of the accessing pointer, because the
174// vseg is not easily accessible at the required time (would required
175// knowing for every syscall which register each arg came in, and looking
176// there).
177//
178// What I am not checking, and would be difficult, but doesn't matter:
179// - free(p): similar to syscalls, not checking that the p.vseg matches the
180// aseg of the first byte in the block. However, Memcheck does an
181// equivalent "bad free" check using shadow_chunks; indeed, Ptrcheck could
182// do the same check, but there's no point duplicating functionality. So
183// no loss, really.
184//
185// Other:
186// - not doing anything with mprotect(); probably not worth the effort.
187//--------------------------------------------------------------
188
189//--------------------------------------------------------------
190// Todo:
191// - Segments for stack frames. Would detect (some, large) stack
192// over/under-runs, dangling pointers.
193//
194// - Segments for static data. Would detect over/under-runs. Requires
195// reading debug info.
196//--------------------------------------------------------------
197
198//--------------------------------------------------------------
199// Some profiling results:
200// twolf konq date sz
201// 1. started 35.0s 14.7
202// 2. introduced GETV/PUTV 30.2s 10.1
203// 3. inlined check_load_or_store 5.6s 27.5s 10.1
204// 4. (made check_load, check_store4 regparm(0)) (27.9s) (11.0)
205// 5. um, not sure 5.3s 27.3s 10.6
206// ...
207// 6. after big changes, corrections 11.2s 32.8s 14.0
208// 7. removed link-segment chasing in check/L/S 8.9s 30.8s 14.0
209// 8. avoiding do_lea1 if k is a nonptr 8.0s 28.0s 12.9
210//--------------------------------------------------------------
211
212//#include "vg_skin.h"
213
214#include "pub_tool_basics.h"
215#include "pub_tool_libcbase.h"
216#include "pub_tool_libcprint.h"
217#include "pub_tool_libcassert.h"
218#include "pub_tool_mallocfree.h"
219#include "pub_tool_execontext.h"
220#include "pub_tool_hashtable.h"
221#include "pub_tool_tooliface.h"
222#include "pub_tool_replacemalloc.h"
223#include "pub_tool_options.h"
224#include "pub_tool_execontext.h"
225#include "pub_tool_aspacemgr.h" // VG_(am_shadow_malloc)
226#include "pub_tool_vki.h" // VKI_MAX_PAGE_SIZE
227#include "pub_tool_machine.h" // VG_({get,set}_shadow_regs_area) et al
228#include "pub_tool_debuginfo.h" // VG_(get_fnname)
229#include "pub_tool_threadstate.h" // VG_(get_running_tid)
230#include "pub_tool_oset.h"
231#include "pub_tool_vkiscnums.h"
232#include "pub_tool_machine.h"
233#include "pub_tool_wordfm.h"
234#include "pub_tool_xarray.h"
235
236#include "pc_common.h"
237
238//#include "h_list.h"
239#include "h_main.h"
240
241#include "sg_main.h" // sg_instrument_*, and struct _SGEnv
242
243
244
245/*------------------------------------------------------------*/
246/*--- Debug/trace options ---*/
247/*------------------------------------------------------------*/
248
249/* Set to 1 to do sanity checks on Seg values in many places, which
250 checks if bogus Segs are in circulation. Quite expensive from a
251 performance point of view. */
252#define SC_SEGS 0
253
254static ULong stats__client_mallocs = 0;
255static ULong stats__client_frees = 0;
256static ULong stats__segs_allocd = 0;
257static ULong stats__segs_recycled = 0;
sewardj024598e2008-09-18 14:43:05 +0000258
259
260//////////////////////////////////////////////////////////////
261// //
262// Segments low level storage //
263// //
264//////////////////////////////////////////////////////////////
265
266// NONPTR, UNKNOWN, BOTTOM defined in h_main.h since
267// pc_common.c needs to see them, for error processing
268
269// we only start recycling segs when this many exist
270#define N_FREED_SEGS (1 * 1000 * 1000)
271
272struct _Seg {
273 Addr addr;
274 SizeT szB; /* may be zero */
275 ExeContext* ec; /* where malloc'd or freed */
276 /* When 1, indicates block is in use. Otherwise, used to form a
277 linked list of freed blocks, running from oldest freed block to
278 the most recently freed block. */
279 struct _Seg* nextfree;
280};
281
282// Determines if 'a' is before, within, or after seg's range. Sets 'cmp' to
283// -1/0/1 accordingly. Sets 'n' to the number of bytes before/within/after.
284void Seg__cmp(Seg* seg, Addr a, Int* cmp, UWord* n)
285{
286 if (a < seg->addr) {
287 *cmp = -1;
288 *n = seg->addr - a;
289 } else if (a < seg->addr + seg->szB && seg->szB > 0) {
290 *cmp = 0;
291 *n = a - seg->addr;
292 } else {
293 *cmp = 1;
294 *n = a - (seg->addr + seg->szB);
295 }
296}
297
298inline Bool Seg__is_freed(Seg* seg)
299{
300 if (!is_known_segment(seg))
301 return False;
302 else
303 return seg->nextfree != (Seg*)1;
304}
305
306ExeContext* Seg__where(Seg* seg)
307{
308 tl_assert(is_known_segment(seg));
309 return seg->ec;
310}
311
312SizeT Seg__size(Seg* seg)
313{
314 tl_assert(is_known_segment(seg));
315 return seg->szB;
316}
317
318Addr Seg__addr(Seg* seg)
319{
320 tl_assert(is_known_segment(seg));
321 return seg->addr;
322}
323
324
325#define N_SEGS_PER_GROUP 10000
326
327typedef
328 struct _SegGroup {
329 struct _SegGroup* admin;
330 UWord nextfree; /* 0 .. N_SEGS_PER_GROUP */
331 Seg segs[N_SEGS_PER_GROUP];
332 }
333 SegGroup;
334
335static SegGroup* group_list = NULL;
336static UWord nFreeSegs = 0;
337static Seg* freesegs_youngest = NULL;
338static Seg* freesegs_oldest = NULL;
339
340
341static SegGroup* new_SegGroup ( void ) {
342 SegGroup* g = VG_(malloc)("pc.h_main.nTG.1", sizeof(SegGroup));
343 VG_(memset)(g, 0, sizeof(*g));
344 return g;
345}
346
347/* Get a completely new Seg */
348static Seg* new_Seg ( void )
349{
350 Seg* teg;
351 SegGroup* g;
352 if (group_list == NULL) {
353 g = new_SegGroup();
354 g->admin = NULL;
355 group_list = g;
356 }
357 tl_assert(group_list->nextfree <= N_SEGS_PER_GROUP);
358 if (group_list->nextfree == N_SEGS_PER_GROUP) {
359 g = new_SegGroup();
360 g->admin = group_list;
361 group_list = g;
362 }
363 tl_assert(group_list->nextfree < N_SEGS_PER_GROUP);
364 teg = &group_list->segs[ group_list->nextfree ];
365 group_list->nextfree++;
366 stats__segs_allocd++;
367 return teg;
368}
369
370static Seg* get_Seg_for_malloc ( void )
371{
372 Seg* seg;
373 if (nFreeSegs < N_FREED_SEGS) {
374 seg = new_Seg();
375 seg->nextfree = (Seg*)1;
376 return seg;
377 }
378 /* else recycle the oldest Seg in the free list */
379 tl_assert(freesegs_youngest);
380 tl_assert(freesegs_oldest);
381 tl_assert(freesegs_youngest != freesegs_oldest);
382 seg = freesegs_oldest;
383 freesegs_oldest = seg->nextfree;
384 nFreeSegs--;
385 seg->nextfree = (Seg*)1;
386 stats__segs_recycled++;
387 return seg;
388}
389
390static void set_Seg_freed ( Seg* seg )
391{
392 tl_assert(seg);
393 tl_assert(!Seg__is_freed(seg));
394 if (nFreeSegs == 0) {
395 tl_assert(freesegs_oldest == NULL);
396 tl_assert(freesegs_youngest == NULL);
397 seg->nextfree = NULL;
398 freesegs_youngest = seg;
399 freesegs_oldest = seg;
400 nFreeSegs++;
401 } else {
402 tl_assert(freesegs_youngest);
403 tl_assert(freesegs_oldest);
404 if (nFreeSegs == 1) {
405 tl_assert(freesegs_youngest == freesegs_oldest);
406 } else {
407 tl_assert(freesegs_youngest != freesegs_oldest);
408 }
409 tl_assert(freesegs_youngest->nextfree == NULL);
410 tl_assert(seg != freesegs_youngest && seg != freesegs_oldest);
411 seg->nextfree = NULL;
412 freesegs_youngest->nextfree = seg;
413 freesegs_youngest = seg;
414 nFreeSegs++;
415 }
416}
417
sewardj95208452008-10-18 19:55:31 +0000418static WordFM* addr_to_seg_map = NULL; /* GuestAddr -> Seg* */
sewardj024598e2008-09-18 14:43:05 +0000419
420static void addr_to_seg_map_ENSURE_INIT ( void )
421{
422 if (UNLIKELY(addr_to_seg_map == NULL)) {
423 addr_to_seg_map = VG_(newFM)( VG_(malloc), "pc.h_main.attmEI.1",
sewardj95208452008-10-18 19:55:31 +0000424 VG_(free), NULL/*unboxedcmp*/ );
sewardj024598e2008-09-18 14:43:05 +0000425 }
426}
427
428static Seg* find_Seg_by_addr ( Addr ga )
429{
430 UWord keyW, valW;
431 addr_to_seg_map_ENSURE_INIT();
432 if (VG_(lookupFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga )) {
433 tl_assert(keyW == ga);
434 return (Seg*)valW;
435 } else {
436 return NULL;
437 }
438}
439
440static void bind_addr_to_Seg ( Addr ga, Seg* seg )
441{
442 Bool b;
443 addr_to_seg_map_ENSURE_INIT();
444 b = VG_(addToFM)( addr_to_seg_map, (UWord)ga, (UWord)seg );
445 tl_assert(!b); /* else ga is already bound */
446}
447
448static void unbind_addr_from_Seg ( Addr ga )
449{
450 Bool b;
451 UWord keyW, valW;
452 addr_to_seg_map_ENSURE_INIT();
453 b = VG_(delFromFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga );
454 tl_assert(b); /* else ga was not already bound */
455 tl_assert(keyW == ga);
456 tl_assert(valW != 0);
457}
458
459
460//////////////////////////////////////////////////////////////
461//////////////////////////////////////////////////////////////
462//////////////////////////////////////////////////////////////
463
464// So that post_reg_write_clientcall knows the segment just allocated.
465static Seg* last_seg_added = NULL;
466
467// Returns the added heap segment
468static Seg* add_new_segment ( ThreadId tid, Addr p, SizeT size )
469{
470 Seg* seg = get_Seg_for_malloc();
471 tl_assert(seg != (Seg*)1); /* since we're using 1 as a special value */
472 seg->addr = p;
473 seg->szB = size;
474 seg->ec = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ );
475 tl_assert(!Seg__is_freed(seg));
476
477 bind_addr_to_Seg(p, seg);
478
479 last_seg_added = seg;
480
481 return seg;
482}
483
484// Forward declarations
485static void copy_mem( Addr from, Addr to, SizeT len );
486static void set_mem_unknown ( Addr a, SizeT len );
487
488static inline VG_REGPARM(1) Seg* nonptr_or_unknown(UWord x); /*fwds*/
489
490static
491void* alloc_and_new_mem_heap ( ThreadId tid,
492 SizeT size, SizeT alignment, Bool is_zeroed )
493{
494 Addr p;
495
496 if ( ((SSizeT)size) < 0) return NULL;
497
498 p = (Addr)VG_(cli_malloc)(alignment, size);
499 if (is_zeroed) VG_(memset)((void*)p, 0, size);
500
501 set_mem_unknown( p, size );
502 add_new_segment( tid, p, size );
503
504 stats__client_mallocs++;
505 return (void*)p;
506}
507
508static void die_and_free_mem_heap ( ThreadId tid, Seg* seg )
509{
510 // Empty and free the actual block
511 tl_assert(!Seg__is_freed(seg));
512 set_mem_unknown( seg->addr, seg->szB );
513
514 VG_(cli_free)( (void*)seg->addr );
515
516 // Remember where freed
517 seg->ec = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ );
518
519 set_Seg_freed(seg);
520 unbind_addr_from_Seg( seg->addr );
521
522 stats__client_frees++;
523}
524
525static void handle_free_heap( ThreadId tid, void* p )
526{
527 Seg* seg = find_Seg_by_addr( (Addr)p );
528 if (!seg) {
529 /* freeing a block that wasn't malloc'd. Ignore. */
530 return;
531 }
532 die_and_free_mem_heap( tid, seg );
533}
534
535
536/*------------------------------------------------------------*/
537/*--- Shadow memory ---*/
538/*------------------------------------------------------------*/
539
540/* Shadow memory holds one Seg for each naturally aligned (guest)
541 word. For a 32 bit target (assuming host word size == guest word
542 size) that means one Seg per 4 bytes, and each Seg occupies 4
543 bytes. For a 64 bit target that means one Seg per 8 bytes, and
544 each Seg occupies 8 bytes. Hence in each case the overall space
545 overhead for shadow memory is 1:1.
546
547 This does however make it a bit tricky to size SecMap.vseg[], simce
548 it needs to hold 16384 entries for 32 bit targets but only 8192
549 entries for 64 bit targets. */
550
551#if 0
552__attribute__((unused))
553static void pp_curr_ExeContext(void)
554{
555 VG_(pp_ExeContext)(
556 VG_(get_ExeContext)(
557 VG_(get_current_or_recent_tid)() ) );
558 VG_(message)(Vg_UserMsg, "");
559}
560#endif
561
sewardj4cb6bf72010-01-01 18:31:41 +0000562#if defined(VGA_x86) || defined(VGA_ppc32) || defined(VGA_arm)
sewardj024598e2008-09-18 14:43:05 +0000563# define SHMEM_SECMAP_MASK 0xFFFC
564# define SHMEM_SECMAP_SHIFT 2
565# define SHMEM_IS_WORD_ALIGNED(_a) VG_IS_4_ALIGNED(_a)
566# define SEC_MAP_WORDS (0x10000UL / 4UL) /* 16k */
567#elif defined(VGA_amd64) || defined(VGA_ppc64)
568# define SHMEM_SECMAP_MASK 0xFFF8
569# define SHMEM_SECMAP_SHIFT 3
570# define SHMEM_IS_WORD_ALIGNED(_a) VG_IS_8_ALIGNED(_a)
571# define SEC_MAP_WORDS (0x10000UL / 8UL) /* 8k */
572#else
573# error "Unknown arch"
574#endif
575
576typedef
577 struct {
578 Seg* vseg[SEC_MAP_WORDS];
579 }
580 SecMap;
581
582static SecMap distinguished_secondary_map;
583
584/* An entry in the primary map. base must be a 64k-aligned value, and
585 sm points at the relevant secondary map. The secondary may be
586 either a real secondary, or the distinguished secondary. DO NOT
587 CHANGE THIS LAYOUT: the first word has to be the key for OSet fast
588 lookups.
589*/
590typedef
591 struct {
592 Addr base;
593 SecMap* sm;
594 }
595 PriMapEnt;
596
597/* Primary map is an OSet of PriMapEnt (primap_L2), "fronted" by a
598 cache (primap_L1). */
599
600/* Tunable parameter: How big is the L1 queue? */
601#define N_PRIMAP_L1 24
602
603/* Tunable parameter: How far along the L1 queue to insert
604 entries resulting from L2 lookups? */
605#define PRIMAP_L1_INSERT_IX 12
606
607static struct {
608 Addr base; // must be 64k aligned
609 PriMapEnt* ent; // pointer to the matching primap_L2 node
610 }
611 primap_L1[N_PRIMAP_L1];
612
613static OSet* primap_L2 = NULL;
614
615
616/* # searches initiated in auxmap_L1, and # base cmps required */
617static ULong n_primap_L1_searches = 0;
618static ULong n_primap_L1_cmps = 0;
619/* # of searches that missed in auxmap_L1 and therefore had to
620 be handed to auxmap_L2. And the number of nodes inserted. */
621static ULong n_primap_L2_searches = 0;
622static ULong n_primap_L2_nodes = 0;
623
624
625static void init_shadow_memory ( void )
626{
627 Int i;
628
629 for (i = 0; i < SEC_MAP_WORDS; i++)
630 distinguished_secondary_map.vseg[i] = NONPTR;
631
632 for (i = 0; i < N_PRIMAP_L1; i++) {
633 primap_L1[i].base = 1; /* not 64k aligned, so doesn't match any
634 request ==> slot is empty */
635 primap_L1[i].ent = NULL;
636 }
637
638 tl_assert(0 == offsetof(PriMapEnt,base));
639 tl_assert(sizeof(Addr) == sizeof(void*));
640 primap_L2 = VG_(OSetGen_Create)( /*keyOff*/ offsetof(PriMapEnt,base),
641 /*fastCmp*/ NULL,
642 VG_(malloc), "pc.h_main.ism.1",
643 VG_(free) );
644 tl_assert(primap_L2);
645}
646
647static void insert_into_primap_L1_at ( Word rank, PriMapEnt* ent )
648{
649 Word i;
650 tl_assert(ent);
651 tl_assert(rank >= 0 && rank < N_PRIMAP_L1);
652 for (i = N_PRIMAP_L1-1; i > rank; i--)
653 primap_L1[i] = primap_L1[i-1];
654 primap_L1[rank].base = ent->base;
655 primap_L1[rank].ent = ent;
656}
657
658static inline PriMapEnt* maybe_find_in_primap ( Addr a )
659{
660 PriMapEnt key;
661 PriMapEnt* res;
662 Word i;
663
664 a &= ~(Addr)0xFFFF;
665
666 /* First search the front-cache, which is a self-organising
667 list containing the most popular entries. */
668
669 if (LIKELY(primap_L1[0].base == a))
670 return primap_L1[0].ent;
671 if (LIKELY(primap_L1[1].base == a)) {
672 Addr t_base = primap_L1[0].base;
673 PriMapEnt* t_ent = primap_L1[0].ent;
674 primap_L1[0].base = primap_L1[1].base;
675 primap_L1[0].ent = primap_L1[1].ent;
676 primap_L1[1].base = t_base;
677 primap_L1[1].ent = t_ent;
678 return primap_L1[0].ent;
679 }
680
681 n_primap_L1_searches++;
682
683 for (i = 0; i < N_PRIMAP_L1; i++) {
684 if (primap_L1[i].base == a) {
685 break;
686 }
687 }
688 tl_assert(i >= 0 && i <= N_PRIMAP_L1);
689
690 n_primap_L1_cmps += (ULong)(i+1);
691
692 if (i < N_PRIMAP_L1) {
693 if (i > 0) {
694 Addr t_base = primap_L1[i-1].base;
695 PriMapEnt* t_ent = primap_L1[i-1].ent;
696 primap_L1[i-1].base = primap_L1[i-0].base;
697 primap_L1[i-1].ent = primap_L1[i-0].ent;
698 primap_L1[i-0].base = t_base;
699 primap_L1[i-0].ent = t_ent;
700 i--;
701 }
702 return primap_L1[i].ent;
703 }
704
705 n_primap_L2_searches++;
706
707 /* First see if we already have it. */
708 key.base = a;
709 key.sm = 0;
710
711 res = VG_(OSetGen_Lookup)(primap_L2, &key);
712 if (res)
713 insert_into_primap_L1_at( PRIMAP_L1_INSERT_IX, res );
714 return res;
715}
716
717static SecMap* alloc_secondary_map ( void )
718{
719 SecMap* map;
720 UInt i;
721
722 // JRS 2008-June-25: what's the following assertion for?
723 tl_assert(0 == (sizeof(SecMap) % VKI_MAX_PAGE_SIZE));
724
725 map = VG_(am_shadow_alloc)( sizeof(SecMap) );
726 if (map == NULL)
727 VG_(out_of_memory_NORETURN)( "annelid:allocate new SecMap",
728 sizeof(SecMap) );
729
730 for (i = 0; i < SEC_MAP_WORDS; i++)
731 map->vseg[i] = NONPTR;
732 if (0) VG_(printf)("XXX new secmap %p\n", map);
733 return map;
734}
735
736static PriMapEnt* find_or_alloc_in_primap ( Addr a )
737{
738 PriMapEnt *nyu, *res;
739
740 /* First see if we already have it. */
741 res = maybe_find_in_primap( a );
742 if (LIKELY(res))
743 return res;
744
745 /* Ok, there's no entry in the secondary map, so we'll have
746 to allocate one. */
747 a &= ~(Addr)0xFFFF;
748
749 nyu = (PriMapEnt*) VG_(OSetGen_AllocNode)(
750 primap_L2, sizeof(PriMapEnt) );
751 tl_assert(nyu);
752 nyu->base = a;
753 nyu->sm = alloc_secondary_map();
754 tl_assert(nyu->sm);
755 VG_(OSetGen_Insert)( primap_L2, nyu );
756 insert_into_primap_L1_at( PRIMAP_L1_INSERT_IX, nyu );
757 n_primap_L2_nodes++;
758 return nyu;
759}
760
761/////////////////////////////////////////////////
762
763// Nb: 'a' must be naturally word aligned for the host.
764static inline Seg* get_mem_vseg ( Addr a )
765{
766 SecMap* sm = find_or_alloc_in_primap(a)->sm;
767 UWord sm_off = (a & SHMEM_SECMAP_MASK) >> SHMEM_SECMAP_SHIFT;
768 tl_assert(SHMEM_IS_WORD_ALIGNED(a));
769 return sm->vseg[sm_off];
770}
771
772// Nb: 'a' must be naturally word aligned for the host.
773static inline void set_mem_vseg ( Addr a, Seg* vseg )
774{
775 SecMap* sm = find_or_alloc_in_primap(a)->sm;
776 UWord sm_off = (a & SHMEM_SECMAP_MASK) >> SHMEM_SECMAP_SHIFT;
777 tl_assert(SHMEM_IS_WORD_ALIGNED(a));
778 sm->vseg[sm_off] = vseg;
779}
780
sewardj95208452008-10-18 19:55:31 +0000781// Find the Seg which contains the given address.
sewardj024598e2008-09-18 14:43:05 +0000782// Returns UNKNOWN if no matches. Never returns BOTTOM or NONPTR.
783// Also, only returns in-use segments, not freed ones.
sewardj95208452008-10-18 19:55:31 +0000784/* Doing this fast is distinctly difficult when there are more than a
785 few heap allocated blocks live. Basically it is done by searching
786 addr_to_seg_map for 'a'.
787
788 First, if 'a' is the start address of a segment, then we can detect
789 that by simply doing a VG_(lookupFM) of 'a', and we are done (nice
790 and easy).
791
792 If 'a' is within some segment, but does not point to the start, it
793 is much more complex. We use VG_(findBoundsFM) to find the segment
794 with the largest .addr field which is <= a, and we then inspect the
795 segment to see if 'a' really falls inside it or not. This is all a
796 bit complex and fragile, and so there's a lot of assertery in the
797 code below. It has been crosschecked however against the trivial
798 _SLOW implementation shown after the end of this fn.
799*/
800static Seg* get_Seg_containing_addr( Addr a )
801{
802 UWord keyW, valW;
803 Seg* s2;
804
805 /* Since we are going to poke around in it */
806 addr_to_seg_map_ENSURE_INIT();
807
808 /* first, see if 'a' is at the start of a block. We do this both
809 because it's easy and more imporantly because VG_(findBoundsFM)
810 will fail in this case, so we need to exclude it first. */
811 if (VG_(lookupFM)( addr_to_seg_map, &keyW, &valW, a )) {
812 tl_assert(keyW == a);
813 s2 = (Seg*)valW;
814 tl_assert(s2->addr == a);
815 } else {
816 Bool ok;
817 UWord kMin, vMin, kMax, vMax;
818 Seg minSeg;
819 Seg maxSeg;
820 UWord minAddr = 0;
821 UWord maxAddr = ~minAddr;
822 VG_(memset)(&minSeg, 0, sizeof(minSeg));
823 VG_(memset)(&maxSeg, 0, sizeof(maxSeg));
824 minSeg.addr = minAddr;
825 maxSeg.addr = maxAddr;
826 ok = VG_(findBoundsFM)( addr_to_seg_map,
827 &kMin, &vMin, &kMax, &vMax,
828 minAddr, (UWord)&minSeg,
829 maxAddr, (UWord)&maxSeg, a );
830 tl_assert(ok); /* must be so, since False is only returned when
831 'a' is directly present in the map, and we
832 just established that it isn't. */
833 /* At this point, either vMin points at minSeg, or it points at a
834 real Seg. In the former case, there is no live heap-allocated
835 Seg which has a start address <= a, so a is not in any block.
836 In the latter case, the Seg vMin points at may or may not
837 actually contain 'a'; we can only tell that by inspecting the
838 Seg itself. */
839 s2 = (Seg*)vMin;
840 tl_assert(kMin == s2->addr);
841 if (s2 == &minSeg) {
842 /* the former */
843 s2 = UNKNOWN;
844 } else {
845 /* the latter */
846 tl_assert(s2->addr <= a);
847 /* if s2 doesn't actually contain 'a', we must forget about it. */
848 if (s2->szB == 0 /* a zero sized block can't contain anything */
849 || s2->addr + s2->szB < a /* the usual range check */)
850 s2 = UNKNOWN;
851 }
852 /* while we're at it, do as much assertery as we can, since this
853 is all rather complex. Either vMax points at maxSeg, or it
854 points to a real block, which must have a start address
855 greater than a. */
856 tl_assert(kMax == ((Seg*)vMax)->addr);
sewardjad039492009-01-29 08:44:49 +0000857 if (vMax == (UWord)&maxSeg) {
sewardj95208452008-10-18 19:55:31 +0000858 /* nothing we can check */
859 } else {
860 tl_assert(a < kMax); /* hence also a < ((Seg*)vMax)->addr */
861 }
862 }
863
864 return s2;
865}
866
867/* XXXX very slow reference implementation. Do not use.
sewardj024598e2008-09-18 14:43:05 +0000868static Seg* get_Seg_containing_addr_SLOW( Addr a )
869{
870 SegGroup* group;
871 UWord i;
872 stats__slow_searches++;
873 for (group = group_list; group; group = group->admin) {
874 for (i = 0; i < group->nextfree; i++) {
875 stats__slow_totcmps++;
876 if (Seg__is_freed(&group->segs[i]))
877 continue;
878 if (group->segs[i].addr <= a
879 && a < group->segs[i].addr + group->segs[i].szB)
880 return &group->segs[i];
881 }
882 }
883 return UNKNOWN;
884}
sewardj95208452008-10-18 19:55:31 +0000885*/
886
sewardj024598e2008-09-18 14:43:05 +0000887
888
889/*------------------------------------------------------------*/
890/*--- malloc() et al replacements ---*/
891/*------------------------------------------------------------*/
892
893void* h_replace_malloc ( ThreadId tid, SizeT n )
894{
895 return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment),
896 /*is_zeroed*/False );
897}
898
899void* h_replace___builtin_new ( ThreadId tid, SizeT n )
900{
901 return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment),
902 /*is_zeroed*/False );
903}
904
905void* h_replace___builtin_vec_new ( ThreadId tid, SizeT n )
906{
907 return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment),
908 /*is_zeroed*/False );
909}
910
911void* h_replace_memalign ( ThreadId tid, SizeT align, SizeT n )
912{
913 return alloc_and_new_mem_heap ( tid, n, align,
914 /*is_zeroed*/False );
915}
916
917void* h_replace_calloc ( ThreadId tid, SizeT nmemb, SizeT size1 )
918{
919 return alloc_and_new_mem_heap ( tid, nmemb*size1, VG_(clo_alignment),
920 /*is_zeroed*/True );
921}
922
923void h_replace_free ( ThreadId tid, void* p )
924{
925 // Should arguably check here if p.vseg matches the segID of the
926 // pointed-to block... unfortunately, by this stage, we don't know what
927 // p.vseg is, because we don't know the address of p (the p here is a
928 // copy, and we've lost the address of its source). To do so would
929 // require passing &p in, which would require rewriting part of
930 // vg_replace_malloc.c... argh.
931 //
932 // However, Memcheck does free checking, and will catch almost all
933 // violations this checking would have caught. (Would only miss if we
934 // unluckily passed an unrelated pointer to the very start of a heap
935 // block that was unrelated to that block. This is very unlikely!) So
936 // we haven't lost much.
937
938 handle_free_heap(tid, p);
939}
940
941void h_replace___builtin_delete ( ThreadId tid, void* p )
942{
943 handle_free_heap(tid, p);
944}
945
946void h_replace___builtin_vec_delete ( ThreadId tid, void* p )
947{
948 handle_free_heap(tid, p);
949}
950
951void* h_replace_realloc ( ThreadId tid, void* p_old, SizeT new_size )
952{
953 Seg* seg;
954
955 /* First try and find the block. */
956 seg = find_Seg_by_addr( (Addr)p_old );
957 if (!seg)
958 return NULL;
959
960 tl_assert(seg->addr == (Addr)p_old);
961
962 if (new_size <= seg->szB) {
963 /* new size is smaller: allocate, copy from old to new */
964 Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
965 VG_(memcpy)((void*)p_new, p_old, new_size);
966
967 /* Notification: copy retained part */
968 copy_mem ( (Addr)p_old, p_new, new_size );
969
970 /* Free old memory */
971 die_and_free_mem_heap( tid, seg );
972
973 /* This has to be after die_and_free_mem_heap, otherwise the
974 former succeeds in shorting out the new block, not the
975 old, in the case when both are on the same list. */
976 add_new_segment ( tid, p_new, new_size );
977
978 return (void*)p_new;
979 } else {
980 /* new size is bigger: allocate, copy from old to new */
981 Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
982 VG_(memcpy)((void*)p_new, p_old, seg->szB);
983
984 /* Notification: first half kept and copied, second half new */
985 copy_mem ( (Addr)p_old, p_new, seg->szB );
986 set_mem_unknown( p_new + seg->szB, new_size - seg->szB );
987
988 /* Free old memory */
989 die_and_free_mem_heap( tid, seg );
990
991 /* This has to be after die_and_free_mem_heap, otherwise the
992 former succeeds in shorting out the new block, not the old,
993 in the case when both are on the same list. NB jrs
994 2008-Sept-11: not sure if this comment is valid/correct any
995 more -- I suspect not. */
996 add_new_segment ( tid, p_new, new_size );
997
998 return (void*)p_new;
999 }
1000}
1001
njn8b140de2009-02-17 04:31:18 +00001002SizeT h_replace_malloc_usable_size ( ThreadId tid, void* p )
1003{
1004 Seg* seg = find_Seg_by_addr( (Addr)p );
1005
1006 // There may be slop, but pretend there isn't because only the asked-for
1007 // area will have been shadowed properly.
1008 return ( seg ? seg->szB : 0 );
1009}
1010
sewardj024598e2008-09-18 14:43:05 +00001011
1012/*------------------------------------------------------------*/
1013/*--- Memory events ---*/
1014/*------------------------------------------------------------*/
1015
1016static inline
1017void set_mem ( Addr a, SizeT len, Seg* seg )
1018{
1019 Addr end;
1020
1021 if (0 == len)
1022 return;
1023
1024 if (len > 100 * 1000 * 1000)
1025 VG_(message)(Vg_UserMsg,
sewardjc1bc9d12009-07-15 14:50:22 +00001026 "Warning: set address range state: large range %lu\n",
1027 len);
sewardj024598e2008-09-18 14:43:05 +00001028
1029 a = VG_ROUNDDN(a, sizeof(UWord));
1030 end = VG_ROUNDUP(a + len, sizeof(UWord));
1031 for ( ; a < end; a += sizeof(UWord))
1032 set_mem_vseg(a, seg);
1033}
1034
1035static void set_mem_unknown( Addr a, SizeT len )
1036{
1037 set_mem( a, len, UNKNOWN );
1038}
1039
1040//zz static void set_mem_nonptr( Addr a, UInt len )
1041//zz {
1042//zz set_mem( a, len, NONPTR );
1043//zz }
1044
1045void h_new_mem_startup( Addr a, SizeT len,
1046 Bool rr, Bool ww, Bool xx, ULong di_handle )
1047{
1048 if (0) VG_(printf)("new_mem_startup(%#lx,%lu)\n", a, len);
1049 set_mem_unknown( a, len );
1050 //add_new_segment( VG_(get_running_tid)(), a, len, SegMmap );
1051}
1052
1053//zz // XXX: Currently not doing anything with brk() -- new segments, or not?
1054//zz // Proper way to do it would be to grow/shrink a single, special brk segment.
1055//zz //
1056//zz // brk is difficult: it defines a single segment, of changeable size.
1057//zz // It starts off with size zero, at the address given by brk(0). There are
1058//zz // no pointers within the program to it. Any subsequent calls by the
1059//zz // program to brk() (possibly growing or shrinking it) return pointers to
1060//zz // the *end* of the segment (nb: this is the kernel brk(), which is
1061//zz // different to the libc brk()).
1062//zz //
1063//zz // If fixing this, don't forget to update the brk case in SK_(post_syscall).
1064//zz //
1065//zz // Nb: not sure if the return value is the last byte addressible, or one
1066//zz // past the end of the segment.
1067//zz //
1068//zz static void new_mem_brk( Addr a, UInt len )
1069//zz {
1070//zz set_mem_unknown(a, len);
1071//zz //VG_(skin_panic)("can't handle new_mem_brk");
1072//zz }
1073
1074// Not quite right: if you mmap a segment into a specified place, it could
1075// be legitimate to do certain arithmetic with the pointer that it wouldn't
1076// otherwise. Hopefully this is rare, though.
1077void h_new_mem_mmap( Addr a, SizeT len,
1078 Bool rr, Bool ww, Bool xx, ULong di_handle )
1079{
1080 if (0) VG_(printf)("new_mem_mmap(%#lx,%lu)\n", a, len);
1081//zz #if 0
1082//zz Seg seg = NULL;
1083//zz
1084//zz // Check for overlapping segments
1085//zz #if 0
1086//zz is_overlapping_seg___a = a; // 'free' variable
1087//zz is_overlapping_seg___len = len; // 'free' variable
1088//zz seg = (Seg)VG_(HT_first_match) ( mlist, is_overlapping_seg );
1089//zz is_overlapping_seg___a = 0; // paranoia, reset
1090//zz is_overlapping_seg___len = 0; // paranoia, reset
1091//zz #endif
1092//zz
1093//zz // XXX: do this check properly with ISLists
1094//zz
1095//zz if ( ISList__findI( seglist, a, &seg )) {
1096//zz sk_assert(SegMmap == seg->status || SegMmapFree == seg->status);
1097//zz if (SegMmap == seg->status)
1098//zz
1099//zz }
1100//zz
1101//zz if (NULL != seg) {
1102//zz // Right, we found an overlap
1103//zz if (VG_(clo_verbosity) > 1)
1104//zz VG_(message)(Vg_UserMsg, "mmap overlap: old: %#lx, %d; new: %#lx, %d",
1105//zz seg->left, Seg__size(seg), a, len);
1106//zz if (seg->left <= a && a <= seg->right) {
1107//zz // New one truncates end of the old one. Nb: we don't adjust its
1108//zz // size, because the first segment's pointer can be (and for
1109//zz // Konqueror, is) legitimately used to access parts of the second
1110//zz // segment. At least, I assume Konqueror is doing something legal.
1111//zz // so that a size mismatch upon munmap isn't a problem.
1112//zz // seg->size = a - seg->data;
1113//zz // seg->is_truncated_map = True;
1114//zz // if (VG_(clo_verbosity) > 1)
1115//zz // VG_(message)(Vg_UserMsg, "old seg truncated to length %d",
1116//zz // seg->size);
1117//zz } else {
1118//zz VG_(skin_panic)("Can't handle this mmap() overlap case");
1119//zz }
1120//zz }
1121 set_mem_unknown( a, len );
1122 //add_new_segment( VG_(get_running_tid)(), a, len, SegMmap );
1123//zz #endif
1124}
1125
1126static void copy_mem( Addr from, Addr to, SizeT len )
1127{
1128 Addr fromend = from + len;
1129
1130 // Must be aligned due to malloc always returning aligned objects.
1131 tl_assert(VG_IS_8_ALIGNED(from) && VG_IS_8_ALIGNED(to));
1132
1133 // Must only be called with positive len.
1134 if (0 == len)
1135 return;
1136
1137 for ( ; from < fromend; from += sizeof(UWord), to += sizeof(UWord))
1138 set_mem_vseg( to, get_mem_vseg(from) );
1139}
1140
1141//zz // Similar to SK_(realloc)()
1142//zz static void copy_mem_remap( Addr from, Addr to, UInt len )
1143//zz {
1144//zz VG_(skin_panic)("argh: copy_mem_remap");
1145//zz }
1146//zz
1147//zz static void die_mem_brk( Addr a, UInt len )
1148//zz {
1149//zz set_mem_unknown(a, len);
1150//zz // VG_(skin_panic)("can't handle die_mem_brk()");
1151//zz }
1152
1153void h_die_mem_munmap( Addr a, SizeT len )
1154{
1155// handle_free_munmap( (void*)a, len );
1156}
1157
1158// Don't need to check all addresses within the block; in the absence of
1159// discontiguous segments, the segments for the first and last bytes should
1160// be the same. Can't easily check the pointer segment matches the block
1161// segment, unfortunately, but the first/last check should catch most
1162// errors.
1163static void pre_mem_access2 ( CorePart part, ThreadId tid, Char* str,
1164 Addr s/*tart*/, Addr e/*nd*/ )
1165{
1166 Seg *seglo, *seghi;
sewardj024598e2008-09-18 14:43:05 +00001167
1168 // Don't check code being translated -- very slow, and not much point
1169 if (Vg_CoreTranslate == part) return;
1170
1171 // Don't check the signal case -- only happens in core, no need to check
1172 if (Vg_CoreSignal == part) return;
1173
1174 // Only expect syscalls after this point
1175 if (part != Vg_CoreSysCall) {
1176 VG_(printf)("part = %d\n", part);
1177 VG_(tool_panic)("unknown corepart in pre_mem_access2");
1178 }
1179
1180 // Check first and last bytes match
sewardj95208452008-10-18 19:55:31 +00001181 seglo = get_Seg_containing_addr( s );
1182 seghi = get_Seg_containing_addr( e );
sewardj024598e2008-09-18 14:43:05 +00001183 tl_assert( BOTTOM != seglo && NONPTR != seglo );
1184 tl_assert( BOTTOM != seghi && NONPTR != seghi );
1185
njn4c245e52009-03-15 23:25:38 +00001186 /* record an error if start and end are in different, but known segments */
sewardj024598e2008-09-18 14:43:05 +00001187 if (is_known_segment(seglo) && is_known_segment(seghi)
1188 && seglo != seghi) {
1189 h_record_sysparam_error(tid, part, str, s, e, seglo, seghi);
1190 }
1191 else
1192 /* record an error if start is in a known segment but end isn't */
1193 if (is_known_segment(seglo) && !is_known_segment(seghi)) {
1194 h_record_sysparam_error(tid, part, str, s, e, seglo, UNKNOWN);
1195 }
1196 else
1197 /* record an error if end is in a known segment but start isn't */
1198 if (!is_known_segment(seglo) && is_known_segment(seghi)) {
1199 h_record_sysparam_error(tid, part, str, s, e, UNKNOWN, seghi);
1200 }
1201}
1202
1203void h_pre_mem_access ( CorePart part, ThreadId tid, Char* s,
1204 Addr base, SizeT size )
1205{
1206 pre_mem_access2( part, tid, s, base, base + size - 1 );
1207}
1208
1209void h_pre_mem_read_asciiz ( CorePart part, ThreadId tid,
1210 Char* s, Addr lo )
1211{
1212 Addr hi = lo;
1213
1214 // Nb: the '\0' must be included in the lo...hi range
1215 while ('\0' != *(Char*)hi) hi++;
1216 pre_mem_access2( part, tid, s, lo, hi );
1217}
1218
1219//zz static void post_mem_write(Addr a, UInt len)
1220//zz {
1221//zz set_mem_unknown(a, len);
1222//zz }
1223
1224
1225/*------------------------------------------------------------*/
1226/*--- Register event handlers ---*/
1227/*------------------------------------------------------------*/
1228
1229//zz static void post_regs_write_init ( void )
1230//zz {
1231//zz UInt i;
1232//zz for (i = R_EAX; i <= R_EDI; i++)
1233//zz VG_(set_shadow_archreg)( i, (UInt)UNKNOWN );
1234//zz
1235//zz // Don't bother about eflags
1236//zz }
1237
1238// BEGIN move this uglyness to pc_machine.c
1239
1240static inline Bool host_is_big_endian ( void ) {
1241 UInt x = 0x11223344;
1242 return 0x1122 == *(UShort*)(&x);
1243}
1244static inline Bool host_is_little_endian ( void ) {
1245 UInt x = 0x11223344;
1246 return 0x3344 == *(UShort*)(&x);
1247}
1248
1249#define N_INTREGINFO_OFFSETS 4
1250
1251/* Holds the result of a query to 'get_IntRegInfo'. Valid values for
1252 n_offsets are:
1253
1254 -1: means the queried guest state slice exactly matches
1255 one integer register
1256
1257 0: means the queried guest state slice does not overlap any
1258 integer registers
1259
1260 1 .. N_INTREGINFO_OFFSETS: means the queried guest state offset
1261 overlaps n_offsets different integer registers, and their base
1262 offsets are placed in the offsets array.
1263*/
1264typedef
1265 struct {
1266 Int offsets[N_INTREGINFO_OFFSETS];
1267 Int n_offsets;
1268 }
1269 IntRegInfo;
1270
1271
1272#if defined(VGA_x86)
1273# include "libvex_guest_x86.h"
sewardj4cb6bf72010-01-01 18:31:41 +00001274# define PC_SIZEOF_GUEST_STATE sizeof(VexGuestX86State)
sewardj024598e2008-09-18 14:43:05 +00001275#endif
1276
1277#if defined(VGA_amd64)
1278# include "libvex_guest_amd64.h"
sewardj4cb6bf72010-01-01 18:31:41 +00001279# define PC_SIZEOF_GUEST_STATE sizeof(VexGuestAMD64State)
sewardj024598e2008-09-18 14:43:05 +00001280# define PC_OFF_FS_ZERO offsetof(VexGuestAMD64State,guest_FS_ZERO)
1281# define PC_SZB_FS_ZERO sizeof( ((VexGuestAMD64State*)0)->guest_FS_ZERO)
1282#endif
1283
1284#if defined(VGA_ppc32)
1285# include "libvex_guest_ppc32.h"
sewardj4cb6bf72010-01-01 18:31:41 +00001286# define PC_SIZEOF_GUEST_STATE sizeof(VexGuestPPC32State)
sewardj024598e2008-09-18 14:43:05 +00001287#endif
1288
1289#if defined(VGA_ppc64)
1290# include "libvex_guest_ppc64.h"
sewardj4cb6bf72010-01-01 18:31:41 +00001291# define PC_SIZEOF_GUEST_STATE sizeof(VexGuestPPC64State)
1292#endif
1293
1294#if defined(VGA_arm)
1295# include "libvex_guest_arm.h"
1296# define PC_SIZEOF_GUEST_STATE sizeof(VexGuestARMState)
sewardj024598e2008-09-18 14:43:05 +00001297#endif
1298
1299
1300/* See description on definition of type IntRegInfo. */
1301static void get_IntRegInfo ( /*OUT*/IntRegInfo* iii, Int offset, Int szB )
1302{
1303 /* --------------------- x86 --------------------- */
1304
1305# if defined(VGA_x86)
1306
1307# define GOF(_fieldname) \
1308 (offsetof(VexGuestX86State,guest_##_fieldname))
1309
1310 Int o = offset;
1311 Int sz = szB;
1312 Bool is4 = sz == 4;
1313 Bool is21 = sz == 2 || sz == 1;
1314
1315 tl_assert(sz > 0);
1316 tl_assert(host_is_little_endian());
1317
1318 /* Set default state to "does not intersect any int register". */
1319 VG_(memset)( iii, 0, sizeof(*iii) );
1320
1321 /* Exact accesses to integer registers */
1322 if (o == GOF(EAX) && is4) goto exactly1;
1323 if (o == GOF(ECX) && is4) goto exactly1;
1324 if (o == GOF(EDX) && is4) goto exactly1;
1325 if (o == GOF(EBX) && is4) goto exactly1;
1326 if (o == GOF(ESP) && is4) goto exactly1;
1327 if (o == GOF(EBP) && is4) goto exactly1;
1328 if (o == GOF(ESI) && is4) goto exactly1;
1329 if (o == GOF(EDI) && is4) goto exactly1;
1330 if (o == GOF(EIP) && is4) goto none;
sewardj5685ade2009-03-30 02:34:29 +00001331 if (o == GOF(IP_AT_SYSCALL) && is4) goto none;
sewardj024598e2008-09-18 14:43:05 +00001332 if (o == GOF(CC_OP) && is4) goto none;
1333 if (o == GOF(CC_DEP1) && is4) goto none;
1334 if (o == GOF(CC_DEP2) && is4) goto none;
1335 if (o == GOF(CC_NDEP) && is4) goto none;
1336 if (o == GOF(DFLAG) && is4) goto none;
1337 if (o == GOF(IDFLAG) && is4) goto none;
1338 if (o == GOF(ACFLAG) && is4) goto none;
1339
1340 /* Partial accesses to integer registers */
1341 if (o == GOF(EAX) && is21) { o -= 0; goto contains_o; }
1342 if (o == GOF(EAX)+1 && is21) { o -= 1; o -= 0; goto contains_o; }
1343 if (o == GOF(ECX) && is21) { o -= 0; goto contains_o; }
1344 if (o == GOF(ECX)+1 && is21) { o -= 1; o -= 0; goto contains_o; }
1345 if (o == GOF(EBX) && is21) { o -= 0; goto contains_o; }
sewardjdb440982008-10-11 10:18:16 +00001346 if (o == GOF(EBX)+1 && is21) { o -= 1; o -= 0; goto contains_o; }
sewardj024598e2008-09-18 14:43:05 +00001347 if (o == GOF(EDX) && is21) { o -= 0; goto contains_o; }
1348 if (o == GOF(EDX)+1 && is21) { o -= 1; o -= 0; goto contains_o; }
1349 if (o == GOF(ESI) && is21) { o -= 0; goto contains_o; }
1350 if (o == GOF(EDI) && is21) { o -= 0; goto contains_o; }
1351
1352 /* Segment related guff */
1353 if (o == GOF(GS) && sz == 2) goto none;
1354 if (o == GOF(LDT) && is4) goto none;
1355 if (o == GOF(GDT) && is4) goto none;
1356
1357 /* FP admin related */
1358 if (o == GOF(SSEROUND) && is4) goto none;
1359 if (o == GOF(FPROUND) && is4) goto none;
1360 if (o == GOF(EMWARN) && is4) goto none;
1361 if (o == GOF(FTOP) && is4) goto none;
1362 if (o == GOF(FPTAG) && sz == 8) goto none;
1363 if (o == GOF(FC3210) && is4) goto none;
1364
1365 /* xmm registers, including arbitrary sub-parts */
1366 if (o >= GOF(XMM0) && o+sz <= GOF(XMM0)+16) goto none;
1367 if (o >= GOF(XMM1) && o+sz <= GOF(XMM1)+16) goto none;
1368 if (o >= GOF(XMM2) && o+sz <= GOF(XMM2)+16) goto none;
1369 if (o >= GOF(XMM3) && o+sz <= GOF(XMM3)+16) goto none;
1370 if (o >= GOF(XMM4) && o+sz <= GOF(XMM4)+16) goto none;
1371 if (o >= GOF(XMM5) && o+sz <= GOF(XMM5)+16) goto none;
1372 if (o >= GOF(XMM6) && o+sz <= GOF(XMM6)+16) goto none;
1373 if (o >= GOF(XMM7) && o+sz <= GOF(XMM7)+16) goto none;
1374
1375 /* mmx/x87 registers (a bit of a kludge, since 'o' is not checked
1376 to be exactly equal to one of FPREG[0] .. FPREG[7]) */
1377 if (o >= GOF(FPREG[0]) && o < GOF(FPREG[7])+8 && sz == 8) goto none;
1378
1379 /* the entire mmx/x87 register bank in one big piece */
1380 if (o == GOF(FPREG) && sz == 64) goto none;
1381
1382 VG_(printf)("get_IntRegInfo(x86):failing on (%d,%d)\n", o, sz);
1383 tl_assert(0);
1384# undef GOF
1385
1386 /* -------------------- amd64 -------------------- */
1387
1388# elif defined(VGA_amd64)
1389
1390# define GOF(_fieldname) \
1391 (offsetof(VexGuestAMD64State,guest_##_fieldname))
1392
1393 Int o = offset;
1394 Int sz = szB;
1395 Bool is421 = sz == 4 || sz == 2 || sz == 1;
1396 Bool is8 = sz == 8;
1397
1398 tl_assert(sz > 0);
1399 tl_assert(host_is_little_endian());
1400
1401 /* Set default state to "does not intersect any int register". */
1402 VG_(memset)( iii, 0, sizeof(*iii) );
1403
1404 /* Exact accesses to integer registers */
1405 if (o == GOF(RAX) && is8) goto exactly1;
1406 if (o == GOF(RCX) && is8) goto exactly1;
1407 if (o == GOF(RDX) && is8) goto exactly1;
1408 if (o == GOF(RBX) && is8) goto exactly1;
1409 if (o == GOF(RSP) && is8) goto exactly1;
1410 if (o == GOF(RBP) && is8) goto exactly1;
1411 if (o == GOF(RSI) && is8) goto exactly1;
1412 if (o == GOF(RDI) && is8) goto exactly1;
1413 if (o == GOF(R8) && is8) goto exactly1;
1414 if (o == GOF(R9) && is8) goto exactly1;
1415 if (o == GOF(R10) && is8) goto exactly1;
1416 if (o == GOF(R11) && is8) goto exactly1;
1417 if (o == GOF(R12) && is8) goto exactly1;
1418 if (o == GOF(R13) && is8) goto exactly1;
1419 if (o == GOF(R14) && is8) goto exactly1;
1420 if (o == GOF(R15) && is8) goto exactly1;
1421 if (o == GOF(RIP) && is8) goto exactly1;
sewardj5685ade2009-03-30 02:34:29 +00001422 if (o == GOF(IP_AT_SYSCALL) && is8) goto none;
sewardj024598e2008-09-18 14:43:05 +00001423 if (o == GOF(CC_OP) && is8) goto none;
1424 if (o == GOF(CC_DEP1) && is8) goto none;
1425 if (o == GOF(CC_DEP2) && is8) goto none;
1426 if (o == GOF(CC_NDEP) && is8) goto none;
1427 if (o == GOF(DFLAG) && is8) goto none;
1428 if (o == GOF(IDFLAG) && is8) goto none;
1429
1430 /* Partial accesses to integer registers */
1431 if (o == GOF(RAX) && is421) { o -= 0; goto contains_o; }
1432 if (o == GOF(RAX)+1 && is421) { o -= 1; o -= 0; goto contains_o; }
1433 if (o == GOF(RCX) && is421) { o -= 0; goto contains_o; }
1434 if (o == GOF(RCX)+1 && is421) { o -= 1; o -= 0; goto contains_o; }
1435 if (o == GOF(RDX) && is421) { o -= 0; goto contains_o; }
1436 if (o == GOF(RDX)+1 && is421) { o -= 1; o -= 0; goto contains_o; }
1437 if (o == GOF(RBX) && is421) { o -= 0; goto contains_o; }
1438 if (o == GOF(RBX)+1 && is421) { o -= 1; o -= 0; goto contains_o; }
1439 if (o == GOF(RBP) && is421) { o -= 0; goto contains_o; }
1440 if (o == GOF(RSI) && is421) { o -= 0; goto contains_o; }
1441 if (o == GOF(RDI) && is421) { o -= 0; goto contains_o; }
1442 if (o == GOF(R8) && is421) { o -= 0; goto contains_o; }
1443 if (o == GOF(R9) && is421) { o -= 0; goto contains_o; }
1444 if (o == GOF(R10) && is421) { o -= 0; goto contains_o; }
1445 if (o == GOF(R11) && is421) { o -= 0; goto contains_o; }
1446 if (o == GOF(R12) && is421) { o -= 0; goto contains_o; }
1447 if (o == GOF(R13) && is421) { o -= 0; goto contains_o; }
1448 if (o == GOF(R14) && is421) { o -= 0; goto contains_o; }
1449 if (o == GOF(R15) && is421) { o -= 0; goto contains_o; }
1450
1451 /* Segment related guff */
1452 if (o == GOF(FS_ZERO) && is8) goto exactly1;
1453
1454 /* FP admin related */
1455 if (o == GOF(SSEROUND) && is8) goto none;
1456 if (o == GOF(FPROUND) && is8) goto none;
1457 if (o == GOF(EMWARN) && sz == 4) goto none;
1458 if (o == GOF(FTOP) && sz == 4) goto none;
1459 if (o == GOF(FPTAG) && is8) goto none;
1460 if (o == GOF(FC3210) && is8) goto none;
1461
1462 /* xmm registers, including arbitrary sub-parts */
1463 if (o >= GOF(XMM0) && o+sz <= GOF(XMM0)+16) goto none;
1464 if (o >= GOF(XMM1) && o+sz <= GOF(XMM1)+16) goto none;
1465 if (o >= GOF(XMM2) && o+sz <= GOF(XMM2)+16) goto none;
1466 if (o >= GOF(XMM3) && o+sz <= GOF(XMM3)+16) goto none;
1467 if (o >= GOF(XMM4) && o+sz <= GOF(XMM4)+16) goto none;
1468 if (o >= GOF(XMM5) && o+sz <= GOF(XMM5)+16) goto none;
1469 if (o >= GOF(XMM6) && o+sz <= GOF(XMM6)+16) goto none;
1470 if (o >= GOF(XMM7) && o+sz <= GOF(XMM7)+16) goto none;
1471 if (o >= GOF(XMM8) && o+sz <= GOF(XMM8)+16) goto none;
1472 if (o >= GOF(XMM9) && o+sz <= GOF(XMM9)+16) goto none;
1473 if (o >= GOF(XMM10) && o+sz <= GOF(XMM10)+16) goto none;
1474 if (o >= GOF(XMM11) && o+sz <= GOF(XMM11)+16) goto none;
1475 if (o >= GOF(XMM12) && o+sz <= GOF(XMM12)+16) goto none;
1476 if (o >= GOF(XMM13) && o+sz <= GOF(XMM13)+16) goto none;
1477 if (o >= GOF(XMM14) && o+sz <= GOF(XMM14)+16) goto none;
1478 if (o >= GOF(XMM15) && o+sz <= GOF(XMM15)+16) goto none;
1479
1480 /* mmx/x87 registers (a bit of a kludge, since 'o' is not checked
1481 to be exactly equal to one of FPREG[0] .. FPREG[7]) */
1482 if (o >= GOF(FPREG[0]) && o < GOF(FPREG[7])+8 && sz == 8) goto none;
1483
1484 VG_(printf)("get_IntRegInfo(amd64):failing on (%d,%d)\n", o, sz);
1485 tl_assert(0);
1486# undef GOF
1487
1488 /* -------------------- ppc32 -------------------- */
1489
1490# elif defined(VGA_ppc32)
1491
1492# define GOF(_fieldname) \
1493 (offsetof(VexGuestPPC32State,guest_##_fieldname))
1494
1495 Int o = offset;
1496 Int sz = szB;
1497 Bool is4 = sz == 4;
1498 Bool is8 = sz == 8;
1499
1500 tl_assert(sz > 0);
1501 tl_assert(host_is_big_endian());
1502
1503 /* Set default state to "does not intersect any int register". */
1504 VG_(memset)( iii, 0, sizeof(*iii) );
1505
1506 /* Exact accesses to integer registers */
1507 if (o == GOF(GPR0) && is4) goto exactly1;
1508 if (o == GOF(GPR1) && is4) goto exactly1;
1509 if (o == GOF(GPR2) && is4) goto exactly1;
1510 if (o == GOF(GPR3) && is4) goto exactly1;
1511 if (o == GOF(GPR4) && is4) goto exactly1;
1512 if (o == GOF(GPR5) && is4) goto exactly1;
1513 if (o == GOF(GPR6) && is4) goto exactly1;
1514 if (o == GOF(GPR7) && is4) goto exactly1;
1515 if (o == GOF(GPR8) && is4) goto exactly1;
1516 if (o == GOF(GPR9) && is4) goto exactly1;
1517 if (o == GOF(GPR10) && is4) goto exactly1;
1518 if (o == GOF(GPR11) && is4) goto exactly1;
1519 if (o == GOF(GPR12) && is4) goto exactly1;
1520 if (o == GOF(GPR13) && is4) goto exactly1;
1521 if (o == GOF(GPR14) && is4) goto exactly1;
1522 if (o == GOF(GPR15) && is4) goto exactly1;
1523 if (o == GOF(GPR16) && is4) goto exactly1;
1524 if (o == GOF(GPR17) && is4) goto exactly1;
1525 if (o == GOF(GPR18) && is4) goto exactly1;
1526 if (o == GOF(GPR19) && is4) goto exactly1;
1527 if (o == GOF(GPR20) && is4) goto exactly1;
1528 if (o == GOF(GPR21) && is4) goto exactly1;
1529 if (o == GOF(GPR22) && is4) goto exactly1;
1530 if (o == GOF(GPR23) && is4) goto exactly1;
1531 if (o == GOF(GPR24) && is4) goto exactly1;
1532 if (o == GOF(GPR25) && is4) goto exactly1;
1533 if (o == GOF(GPR26) && is4) goto exactly1;
1534 if (o == GOF(GPR27) && is4) goto exactly1;
1535 if (o == GOF(GPR28) && is4) goto exactly1;
1536 if (o == GOF(GPR29) && is4) goto exactly1;
1537 if (o == GOF(GPR30) && is4) goto exactly1;
1538 if (o == GOF(GPR31) && is4) goto exactly1;
1539
1540 /* Misc integer reg and condition code accesses */
1541 if (o == GOF(LR) && is4) goto exactly1;
1542 if (o == GOF(CTR) && is4) goto exactly1;
1543 if (o == GOF(CIA) && is4) goto none;
sewardj90fc9d72009-03-20 00:28:50 +00001544 if (o == GOF(IP_AT_SYSCALL) && is4) goto none;
sewardj024598e2008-09-18 14:43:05 +00001545 if (o == GOF(TISTART) && is4) goto none;
1546 if (o == GOF(TILEN) && is4) goto none;
1547 if (o == GOF(REDIR_SP) && is4) goto none;
1548
1549 if (sz == 1) {
1550 if (o == GOF(XER_SO)) goto none;
1551 if (o == GOF(XER_OV)) goto none;
1552 if (o == GOF(XER_CA)) goto none;
1553 if (o == GOF(XER_BC)) goto none;
1554 if (o == GOF(CR0_321)) goto none;
1555 if (o == GOF(CR0_0)) goto none;
1556 if (o == GOF(CR1_321)) goto none;
1557 if (o == GOF(CR1_0)) goto none;
1558 if (o == GOF(CR2_321)) goto none;
1559 if (o == GOF(CR2_0)) goto none;
1560 if (o == GOF(CR3_321)) goto none;
1561 if (o == GOF(CR3_0)) goto none;
1562 if (o == GOF(CR4_321)) goto none;
1563 if (o == GOF(CR4_0)) goto none;
1564 if (o == GOF(CR5_321)) goto none;
1565 if (o == GOF(CR5_0)) goto none;
1566 if (o == GOF(CR6_321)) goto none;
1567 if (o == GOF(CR6_0)) goto none;
1568 if (o == GOF(CR7_321)) goto none;
1569 if (o == GOF(CR7_0)) goto none;
1570 }
1571
1572 /* Exact accesses to FP registers */
1573 if (o == GOF(FPR0) && is8) goto none;
1574 if (o == GOF(FPR1) && is8) goto none;
1575 if (o == GOF(FPR2) && is8) goto none;
1576 if (o == GOF(FPR3) && is8) goto none;
1577 if (o == GOF(FPR4) && is8) goto none;
1578 if (o == GOF(FPR5) && is8) goto none;
1579 if (o == GOF(FPR6) && is8) goto none;
1580 if (o == GOF(FPR7) && is8) goto none;
1581 if (o == GOF(FPR8) && is8) goto none;
1582 if (o == GOF(FPR9) && is8) goto none;
1583 if (o == GOF(FPR10) && is8) goto none;
1584 if (o == GOF(FPR11) && is8) goto none;
1585 if (o == GOF(FPR12) && is8) goto none;
1586 if (o == GOF(FPR13) && is8) goto none;
1587 if (o == GOF(FPR14) && is8) goto none;
1588 if (o == GOF(FPR15) && is8) goto none;
1589 if (o == GOF(FPR16) && is8) goto none;
1590 if (o == GOF(FPR17) && is8) goto none;
1591 if (o == GOF(FPR18) && is8) goto none;
1592 if (o == GOF(FPR19) && is8) goto none;
1593 if (o == GOF(FPR20) && is8) goto none;
1594 if (o == GOF(FPR21) && is8) goto none;
1595 if (o == GOF(FPR22) && is8) goto none;
1596 if (o == GOF(FPR23) && is8) goto none;
1597 if (o == GOF(FPR24) && is8) goto none;
1598 if (o == GOF(FPR25) && is8) goto none;
1599 if (o == GOF(FPR26) && is8) goto none;
1600 if (o == GOF(FPR27) && is8) goto none;
1601 if (o == GOF(FPR28) && is8) goto none;
1602 if (o == GOF(FPR29) && is8) goto none;
1603 if (o == GOF(FPR30) && is8) goto none;
1604 if (o == GOF(FPR31) && is8) goto none;
1605
1606 /* FP admin related */
1607 if (o == GOF(FPROUND) && is4) goto none;
1608 if (o == GOF(EMWARN) && is4) goto none;
1609
1610 /* Altivec registers */
1611 if (o == GOF(VR0) && sz == 16) goto none;
1612 if (o == GOF(VR1) && sz == 16) goto none;
1613 if (o == GOF(VR2) && sz == 16) goto none;
1614 if (o == GOF(VR3) && sz == 16) goto none;
1615 if (o == GOF(VR4) && sz == 16) goto none;
1616 if (o == GOF(VR5) && sz == 16) goto none;
1617 if (o == GOF(VR6) && sz == 16) goto none;
1618 if (o == GOF(VR7) && sz == 16) goto none;
1619 if (o == GOF(VR8) && sz == 16) goto none;
1620 if (o == GOF(VR9) && sz == 16) goto none;
1621 if (o == GOF(VR10) && sz == 16) goto none;
1622 if (o == GOF(VR11) && sz == 16) goto none;
1623 if (o == GOF(VR12) && sz == 16) goto none;
1624 if (o == GOF(VR13) && sz == 16) goto none;
1625 if (o == GOF(VR14) && sz == 16) goto none;
1626 if (o == GOF(VR15) && sz == 16) goto none;
1627 if (o == GOF(VR16) && sz == 16) goto none;
1628 if (o == GOF(VR17) && sz == 16) goto none;
1629 if (o == GOF(VR18) && sz == 16) goto none;
1630 if (o == GOF(VR19) && sz == 16) goto none;
1631 if (o == GOF(VR20) && sz == 16) goto none;
1632 if (o == GOF(VR21) && sz == 16) goto none;
1633 if (o == GOF(VR22) && sz == 16) goto none;
1634 if (o == GOF(VR23) && sz == 16) goto none;
1635 if (o == GOF(VR24) && sz == 16) goto none;
1636 if (o == GOF(VR25) && sz == 16) goto none;
1637 if (o == GOF(VR26) && sz == 16) goto none;
1638 if (o == GOF(VR27) && sz == 16) goto none;
1639 if (o == GOF(VR28) && sz == 16) goto none;
1640 if (o == GOF(VR29) && sz == 16) goto none;
1641 if (o == GOF(VR30) && sz == 16) goto none;
1642 if (o == GOF(VR31) && sz == 16) goto none;
1643
sewardjaae82082008-10-21 23:10:18 +00001644 /* Altivec admin related */
1645 if (o == GOF(VRSAVE) && is4) goto none;
1646
sewardj024598e2008-09-18 14:43:05 +00001647 VG_(printf)("get_IntRegInfo(ppc32):failing on (%d,%d)\n", o, sz);
1648 tl_assert(0);
1649# undef GOF
1650
1651 /* -------------------- ppc64 -------------------- */
1652
1653# elif defined(VGA_ppc64)
1654
1655# define GOF(_fieldname) \
1656 (offsetof(VexGuestPPC64State,guest_##_fieldname))
1657
1658 Int o = offset;
1659 Int sz = szB;
1660 Bool is4 = sz == 4;
1661 Bool is8 = sz == 8;
1662
1663 tl_assert(sz > 0);
1664 tl_assert(host_is_big_endian());
1665
1666 /* Set default state to "does not intersect any int register". */
1667 VG_(memset)( iii, 0, sizeof(*iii) );
1668
1669 /* Exact accesses to integer registers */
1670 if (o == GOF(GPR0) && is8) goto exactly1;
1671 if (o == GOF(GPR1) && is8) goto exactly1;
1672 if (o == GOF(GPR2) && is8) goto exactly1;
1673 if (o == GOF(GPR3) && is8) goto exactly1;
1674 if (o == GOF(GPR4) && is8) goto exactly1;
1675 if (o == GOF(GPR5) && is8) goto exactly1;
1676 if (o == GOF(GPR6) && is8) goto exactly1;
1677 if (o == GOF(GPR7) && is8) goto exactly1;
1678 if (o == GOF(GPR8) && is8) goto exactly1;
1679 if (o == GOF(GPR9) && is8) goto exactly1;
1680 if (o == GOF(GPR10) && is8) goto exactly1;
1681 if (o == GOF(GPR11) && is8) goto exactly1;
1682 if (o == GOF(GPR12) && is8) goto exactly1;
1683 if (o == GOF(GPR13) && is8) goto exactly1;
1684 if (o == GOF(GPR14) && is8) goto exactly1;
1685 if (o == GOF(GPR15) && is8) goto exactly1;
1686 if (o == GOF(GPR16) && is8) goto exactly1;
1687 if (o == GOF(GPR17) && is8) goto exactly1;
1688 if (o == GOF(GPR18) && is8) goto exactly1;
1689 if (o == GOF(GPR19) && is8) goto exactly1;
1690 if (o == GOF(GPR20) && is8) goto exactly1;
1691 if (o == GOF(GPR21) && is8) goto exactly1;
1692 if (o == GOF(GPR22) && is8) goto exactly1;
1693 if (o == GOF(GPR23) && is8) goto exactly1;
1694 if (o == GOF(GPR24) && is8) goto exactly1;
1695 if (o == GOF(GPR25) && is8) goto exactly1;
1696 if (o == GOF(GPR26) && is8) goto exactly1;
1697 if (o == GOF(GPR27) && is8) goto exactly1;
1698 if (o == GOF(GPR28) && is8) goto exactly1;
1699 if (o == GOF(GPR29) && is8) goto exactly1;
1700 if (o == GOF(GPR30) && is8) goto exactly1;
1701 if (o == GOF(GPR31) && is8) goto exactly1;
1702
1703 /* Misc integer reg and condition code accesses */
1704 if (o == GOF(LR) && is8) goto exactly1;
1705 if (o == GOF(CTR) && is8) goto exactly1;
1706 if (o == GOF(CIA) && is8) goto none;
sewardj90fc9d72009-03-20 00:28:50 +00001707 if (o == GOF(IP_AT_SYSCALL) && is8) goto none;
sewardj024598e2008-09-18 14:43:05 +00001708 if (o == GOF(TISTART) && is8) goto none;
1709 if (o == GOF(TILEN) && is8) goto none;
1710 if (o == GOF(REDIR_SP) && is8) goto none;
1711
1712 if (sz == 1) {
1713 if (o == GOF(XER_SO)) goto none;
1714 if (o == GOF(XER_OV)) goto none;
1715 if (o == GOF(XER_CA)) goto none;
1716 if (o == GOF(XER_BC)) goto none;
1717 if (o == GOF(CR0_321)) goto none;
1718 if (o == GOF(CR0_0)) goto none;
1719 if (o == GOF(CR1_321)) goto none;
1720 if (o == GOF(CR1_0)) goto none;
1721 if (o == GOF(CR2_321)) goto none;
1722 if (o == GOF(CR2_0)) goto none;
1723 if (o == GOF(CR3_321)) goto none;
1724 if (o == GOF(CR3_0)) goto none;
1725 if (o == GOF(CR4_321)) goto none;
1726 if (o == GOF(CR4_0)) goto none;
1727 if (o == GOF(CR5_321)) goto none;
1728 if (o == GOF(CR5_0)) goto none;
1729 if (o == GOF(CR6_321)) goto none;
1730 if (o == GOF(CR6_0)) goto none;
1731 if (o == GOF(CR7_321)) goto none;
1732 if (o == GOF(CR7_0)) goto none;
1733 }
1734
1735 /* Exact accesses to FP registers */
1736 if (o == GOF(FPR0) && is8) goto none;
1737 if (o == GOF(FPR1) && is8) goto none;
1738 if (o == GOF(FPR2) && is8) goto none;
1739 if (o == GOF(FPR3) && is8) goto none;
1740 if (o == GOF(FPR4) && is8) goto none;
1741 if (o == GOF(FPR5) && is8) goto none;
1742 if (o == GOF(FPR6) && is8) goto none;
1743 if (o == GOF(FPR7) && is8) goto none;
1744 if (o == GOF(FPR8) && is8) goto none;
1745 if (o == GOF(FPR9) && is8) goto none;
1746 if (o == GOF(FPR10) && is8) goto none;
1747 if (o == GOF(FPR11) && is8) goto none;
1748 if (o == GOF(FPR12) && is8) goto none;
1749 if (o == GOF(FPR13) && is8) goto none;
1750 if (o == GOF(FPR14) && is8) goto none;
1751 if (o == GOF(FPR15) && is8) goto none;
1752 if (o == GOF(FPR16) && is8) goto none;
1753 if (o == GOF(FPR17) && is8) goto none;
1754 if (o == GOF(FPR18) && is8) goto none;
1755 if (o == GOF(FPR19) && is8) goto none;
1756 if (o == GOF(FPR20) && is8) goto none;
1757 if (o == GOF(FPR21) && is8) goto none;
1758 if (o == GOF(FPR22) && is8) goto none;
1759 if (o == GOF(FPR23) && is8) goto none;
1760 if (o == GOF(FPR24) && is8) goto none;
1761 if (o == GOF(FPR25) && is8) goto none;
1762 if (o == GOF(FPR26) && is8) goto none;
1763 if (o == GOF(FPR27) && is8) goto none;
1764 if (o == GOF(FPR28) && is8) goto none;
1765 if (o == GOF(FPR29) && is8) goto none;
1766 if (o == GOF(FPR30) && is8) goto none;
1767 if (o == GOF(FPR31) && is8) goto none;
1768
1769 /* FP admin related */
1770 if (o == GOF(FPROUND) && is4) goto none;
1771 if (o == GOF(EMWARN) && is4) goto none;
1772
1773 /* Altivec registers */
1774 if (o == GOF(VR0) && sz == 16) goto none;
1775 if (o == GOF(VR1) && sz == 16) goto none;
1776 if (o == GOF(VR2) && sz == 16) goto none;
1777 if (o == GOF(VR3) && sz == 16) goto none;
1778 if (o == GOF(VR4) && sz == 16) goto none;
1779 if (o == GOF(VR5) && sz == 16) goto none;
1780 if (o == GOF(VR6) && sz == 16) goto none;
1781 if (o == GOF(VR7) && sz == 16) goto none;
1782 if (o == GOF(VR8) && sz == 16) goto none;
1783 if (o == GOF(VR9) && sz == 16) goto none;
1784 if (o == GOF(VR10) && sz == 16) goto none;
1785 if (o == GOF(VR11) && sz == 16) goto none;
1786 if (o == GOF(VR12) && sz == 16) goto none;
1787 if (o == GOF(VR13) && sz == 16) goto none;
1788 if (o == GOF(VR14) && sz == 16) goto none;
1789 if (o == GOF(VR15) && sz == 16) goto none;
1790 if (o == GOF(VR16) && sz == 16) goto none;
1791 if (o == GOF(VR17) && sz == 16) goto none;
1792 if (o == GOF(VR18) && sz == 16) goto none;
1793 if (o == GOF(VR19) && sz == 16) goto none;
1794 if (o == GOF(VR20) && sz == 16) goto none;
1795 if (o == GOF(VR21) && sz == 16) goto none;
1796 if (o == GOF(VR22) && sz == 16) goto none;
1797 if (o == GOF(VR23) && sz == 16) goto none;
1798 if (o == GOF(VR24) && sz == 16) goto none;
1799 if (o == GOF(VR25) && sz == 16) goto none;
1800 if (o == GOF(VR26) && sz == 16) goto none;
1801 if (o == GOF(VR27) && sz == 16) goto none;
1802 if (o == GOF(VR28) && sz == 16) goto none;
1803 if (o == GOF(VR29) && sz == 16) goto none;
1804 if (o == GOF(VR30) && sz == 16) goto none;
1805 if (o == GOF(VR31) && sz == 16) goto none;
1806
sewardjaae82082008-10-21 23:10:18 +00001807 /* Altivec admin related */
1808 if (o == GOF(VRSAVE) && is4) goto none;
1809
sewardj024598e2008-09-18 14:43:05 +00001810 VG_(printf)("get_IntRegInfo(ppc64):failing on (%d,%d)\n", o, sz);
1811 tl_assert(0);
1812# undef GOF
1813
sewardj4cb6bf72010-01-01 18:31:41 +00001814 /* -------------------- arm -------------------- */
1815
1816# elif defined(VGA_arm)
1817
1818# define GOF(_fieldname) \
1819 (offsetof(VexGuestARMState,guest_##_fieldname))
1820
1821 Int o = offset;
1822 Int sz = szB;
1823 Bool is4 = sz == 4;
1824 Bool is8 = sz == 8;
1825
1826 tl_assert(sz > 0);
1827 tl_assert(host_is_big_endian());
1828
1829 /* Set default state to "does not intersect any int register". */
1830 VG_(memset)( iii, 0, sizeof(*iii) );
1831
1832 VG_(printf)("get_IntRegInfo(arm):failing on (%d,%d)\n", o, sz);
1833 tl_assert(0);
1834
sewardj024598e2008-09-18 14:43:05 +00001835
1836# else
1837# error "FIXME: not implemented for this architecture"
1838# endif
1839
1840 exactly1:
1841 iii->n_offsets = -1;
1842 return;
1843 none:
1844 iii->n_offsets = 0;
1845 return;
1846 contains_o:
1847 tl_assert(o >= 0 && 0 == (o % sizeof(UWord)));
1848 iii->n_offsets = 1;
1849 iii->offsets[0] = o;
1850 return;
1851}
1852
1853
1854/* Does 'arr' describe an indexed guest state section containing host
1855 words, that we want to shadow? */
1856
1857static Bool is_integer_guest_reg_array ( IRRegArray* arr )
1858{
1859 /* --------------------- x86 --------------------- */
1860# if defined(VGA_x86)
1861 /* The x87 tag array. */
1862 if (arr->base == offsetof(VexGuestX86State,guest_FPTAG[0])
1863 && arr->elemTy == Ity_I8 && arr->nElems == 8)
1864 return False;
1865 /* The x87 register array. */
1866 if (arr->base == offsetof(VexGuestX86State,guest_FPREG[0])
1867 && arr->elemTy == Ity_F64 && arr->nElems == 8)
1868 return False;
1869
1870 VG_(printf)("is_integer_guest_reg_array(x86): unhandled: ");
1871 ppIRRegArray(arr);
1872 VG_(printf)("\n");
1873 tl_assert(0);
1874
1875 /* -------------------- amd64 -------------------- */
1876# elif defined(VGA_amd64)
1877 /* The x87 tag array. */
1878 if (arr->base == offsetof(VexGuestAMD64State,guest_FPTAG[0])
1879 && arr->elemTy == Ity_I8 && arr->nElems == 8)
1880 return False;
1881 /* The x87 register array. */
1882 if (arr->base == offsetof(VexGuestAMD64State,guest_FPREG[0])
1883 && arr->elemTy == Ity_F64 && arr->nElems == 8)
1884 return False;
1885
1886 VG_(printf)("is_integer_guest_reg_array(amd64): unhandled: ");
1887 ppIRRegArray(arr);
1888 VG_(printf)("\n");
1889 tl_assert(0);
1890
1891 /* -------------------- ppc32 -------------------- */
1892# elif defined(VGA_ppc32)
1893 /* The redir stack. */
1894 if (arr->base == offsetof(VexGuestPPC32State,guest_REDIR_STACK[0])
1895 && arr->elemTy == Ity_I32
1896 && arr->nElems == VEX_GUEST_PPC32_REDIR_STACK_SIZE)
1897 return True;
1898
1899 VG_(printf)("is_integer_guest_reg_array(ppc32): unhandled: ");
1900 ppIRRegArray(arr);
1901 VG_(printf)("\n");
1902 tl_assert(0);
1903
1904 /* -------------------- ppc64 -------------------- */
1905# elif defined(VGA_ppc64)
1906 /* The redir stack. */
1907 if (arr->base == offsetof(VexGuestPPC64State,guest_REDIR_STACK[0])
1908 && arr->elemTy == Ity_I64
1909 && arr->nElems == VEX_GUEST_PPC64_REDIR_STACK_SIZE)
1910 return True;
1911
1912 VG_(printf)("is_integer_guest_reg_array(ppc64): unhandled: ");
1913 ppIRRegArray(arr);
1914 VG_(printf)("\n");
1915 tl_assert(0);
1916
sewardj4cb6bf72010-01-01 18:31:41 +00001917 /* -------------------- arm -------------------- */
1918# elif defined(VGA_arm)
1919 /* There are no rotating register sections on ARM. */
1920 VG_(printf)("is_integer_guest_reg_array(arm): unhandled: ");
1921 ppIRRegArray(arr);
1922 VG_(printf)("\n");
1923 tl_assert(0);
1924
sewardj024598e2008-09-18 14:43:05 +00001925# else
1926# error "FIXME: not implemented for this architecture"
1927# endif
1928}
1929
1930
1931// END move this uglyness to pc_machine.c
1932
1933/* returns True iff given slice exactly matches an int reg. Merely
1934 a convenience wrapper around get_IntRegInfo. */
1935static Bool is_integer_guest_reg ( Int offset, Int szB )
1936{
1937 IntRegInfo iii;
1938 get_IntRegInfo( &iii, offset, szB );
1939 tl_assert(iii.n_offsets >= -1 && iii.n_offsets <= N_INTREGINFO_OFFSETS);
1940 return iii.n_offsets == -1;
1941}
1942
1943/* these assume guest and host have the same endianness and
1944 word size (probably). */
1945static UWord get_guest_intreg ( ThreadId tid, Int shadowNo,
njnc4431bf2009-01-15 21:29:24 +00001946 PtrdiffT offset, SizeT size )
sewardj024598e2008-09-18 14:43:05 +00001947{
1948 UChar tmp[ 2 + sizeof(UWord) ];
1949 tl_assert(size == sizeof(UWord));
1950 tl_assert(0 == (offset % sizeof(UWord)));
1951 VG_(memset)(tmp, 0, sizeof(tmp));
1952 tmp[0] = 0x31;
1953 tmp[ sizeof(tmp)-1 ] = 0x27;
1954 VG_(get_shadow_regs_area)(tid, &tmp[1], shadowNo, offset, size);
1955 tl_assert(tmp[0] == 0x31);
1956 tl_assert(tmp[ sizeof(tmp)-1 ] == 0x27);
1957 return * ((UWord*) &tmp[1] ); /* MISALIGNED LOAD */
1958}
1959static void put_guest_intreg ( ThreadId tid, Int shadowNo,
njnc4431bf2009-01-15 21:29:24 +00001960 PtrdiffT offset, SizeT size, UWord w )
sewardj024598e2008-09-18 14:43:05 +00001961{
1962 tl_assert(size == sizeof(UWord));
1963 tl_assert(0 == (offset % sizeof(UWord)));
1964 VG_(set_shadow_regs_area)(tid, shadowNo, offset, size,
1965 (const UChar*)&w);
1966}
1967
1968/* Initialise the integer shadow registers to UNKNOWN. This is a bit
1969 of a nasty kludge, but it does mean we don't need to know which
1970 registers we really need to initialise -- simply assume that all
1971 integer registers will be naturally aligned w.r.t. the start of the
1972 guest state, and fill in all possible entries. */
1973static void init_shadow_registers ( ThreadId tid )
1974{
1975 Int i, wordSzB = sizeof(UWord);
sewardj4cb6bf72010-01-01 18:31:41 +00001976 for (i = 0; i < PC_SIZEOF_GUEST_STATE-wordSzB; i += wordSzB) {
sewardj024598e2008-09-18 14:43:05 +00001977 put_guest_intreg( tid, 1, i, wordSzB, (UWord)UNKNOWN );
1978 }
1979}
1980
njnc4431bf2009-01-15 21:29:24 +00001981static void post_reg_write_nonptr ( ThreadId tid, PtrdiffT offset, SizeT size )
sewardj024598e2008-09-18 14:43:05 +00001982{
1983 // syscall_return: Default is non-pointer. If it really is a pointer
1984 // (eg. for mmap()), SK_(post_syscall) sets it again afterwards.
1985 //
1986 // clientreq_return: All the global client requests return non-pointers
1987 // (except possibly CLIENT_CALL[0123], but they're handled by
1988 // post_reg_write_clientcall, not here).
1989 //
1990 if (is_integer_guest_reg( (Int)offset, (Int)size )) {
1991 put_guest_intreg( tid, 1, offset, size, (UWord)NONPTR );
sewardjb87a6392009-07-13 10:00:06 +00001992 }
1993 else
1994 if (size == 1 || size == 2) {
1995 /* can't possibly be an integer guest reg. Ignore. */
1996 }
1997 else {
njnf76d27a2009-05-28 01:53:07 +00001998 // DDD: on Darwin, this assertion fails because we currently do a
1999 // 'post_reg_write' on the 'guest_CC_DEP1' pseudo-register.
sewardjb87a6392009-07-13 10:00:06 +00002000 // JRS 2009July13: we should change is_integer_guest_reg()
2001 // to accept guest_CC_DEP* and guest_CC_NDEP
2002 // as legitimate pointer-holding registers
sewardj024598e2008-09-18 14:43:05 +00002003 tl_assert(0);
2004 }
2005 // VG_(set_thread_shadow_archreg)( tid, reg, (UInt)NONPTR );
2006}
2007
2008static void post_reg_write_nonptr_or_unknown ( ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00002009 PtrdiffT offset, SizeT size )
sewardj024598e2008-09-18 14:43:05 +00002010{
2011 // deliver_signal: called from two places; one sets the reg to zero, the
2012 // other sets the stack pointer.
2013 //
2014 if (is_integer_guest_reg( (Int)offset, (Int)size )) {
2015 put_guest_intreg(
2016 tid, 1/*shadowno*/, offset, size,
2017 (UWord)nonptr_or_unknown(
2018 get_guest_intreg( tid, 0/*shadowno*/,
2019 offset, size )));
2020 } else {
2021 tl_assert(0);
2022 }
2023}
2024
2025void h_post_reg_write_demux ( CorePart part, ThreadId tid,
njnc4431bf2009-01-15 21:29:24 +00002026 PtrdiffT guest_state_offset, SizeT size)
sewardj024598e2008-09-18 14:43:05 +00002027{
2028 if (0)
2029 VG_(printf)("post_reg_write_demux: tid %d part %d off %ld size %ld\n",
2030 (Int)tid, (Int)part,
2031 guest_state_offset, size);
2032 switch (part) {
2033 case Vg_CoreStartup:
2034 /* This is a bit of a kludge since for any Vg_CoreStartup
2035 event we overwrite the entire shadow register set. But
2036 that's ok - we're only called once with
2037 part==Vg_CoreStartup event, and in that case the supplied
2038 offset & size cover the entire guest state anyway. */
2039 init_shadow_registers(tid);
2040 break;
2041 case Vg_CoreSysCall:
2042 if (0) VG_(printf)("ZZZZZZZ p_r_w -> NONPTR\n");
2043 post_reg_write_nonptr( tid, guest_state_offset, size );
2044 break;
2045 case Vg_CoreClientReq:
2046 post_reg_write_nonptr( tid, guest_state_offset, size );
2047 break;
2048 case Vg_CoreSignal:
2049 post_reg_write_nonptr_or_unknown( tid, guest_state_offset, size );
2050 break;
2051 default:
2052 tl_assert(0);
2053 }
2054}
2055
njnc4431bf2009-01-15 21:29:24 +00002056void h_post_reg_write_clientcall(ThreadId tid, PtrdiffT guest_state_offset,
sewardj024598e2008-09-18 14:43:05 +00002057 SizeT size, Addr f )
2058{
2059 UWord p;
2060
2061 // Having to do this is a bit nasty...
2062 if (f == (Addr)h_replace_malloc
2063 || f == (Addr)h_replace___builtin_new
2064 || f == (Addr)h_replace___builtin_vec_new
2065 || f == (Addr)h_replace_calloc
2066 || f == (Addr)h_replace_memalign
2067 || f == (Addr)h_replace_realloc)
2068 {
2069 // We remembered the last added segment; make sure it's the right one.
2070 /* What's going on: at this point, the scheduler has just called
2071 'f' -- one of our malloc replacement functions -- and it has
2072 returned. The return value has been written to the guest
2073 state of thread 'tid', offset 'guest_state_offset' length
2074 'size'. We need to look at that return value and set the
2075 shadow return value accordingly. The shadow return value
2076 required is handed to us "under the counter" through the
2077 global variable 'last_seg_added'. This is all very ugly, not
2078 to mention, non-thread-safe should V ever become
2079 multithreaded. */
2080 /* assert the place where the return value is is a legit int reg */
2081 tl_assert(is_integer_guest_reg(guest_state_offset, size));
2082 /* Now we need to look at the returned value, to see whether the
2083 malloc succeeded or not. */
2084 p = get_guest_intreg(tid, 0/*non-shadow*/, guest_state_offset, size);
2085 if ((UWord)NULL == p) {
2086 // if alloc failed, eg. realloc on bogus pointer
2087 put_guest_intreg(tid, 1/*first-shadow*/,
2088 guest_state_offset, size, (UWord)NONPTR );
2089 } else {
2090 // alloc didn't fail. Check we have the correct segment.
2091 tl_assert(p == last_seg_added->addr);
2092 put_guest_intreg(tid, 1/*first-shadow*/,
2093 guest_state_offset, size, (UWord)last_seg_added );
2094 }
2095 }
2096 else if (f == (Addr)h_replace_free
2097 || f == (Addr)h_replace___builtin_delete
2098 || f == (Addr)h_replace___builtin_vec_delete
sewardjc1bc9d12009-07-15 14:50:22 +00002099 // || f == (Addr)VG_(cli_block_size)
sewardj024598e2008-09-18 14:43:05 +00002100 || f == (Addr)VG_(message))
2101 {
2102 // Probably best to set the (non-existent!) return value to
2103 // non-pointer.
2104 tl_assert(is_integer_guest_reg(guest_state_offset, size));
2105 put_guest_intreg(tid, 1/*first-shadow*/,
2106 guest_state_offset, size, (UWord)NONPTR );
2107 }
2108 else {
2109 // Anything else, probably best to set return value to non-pointer.
2110 //VG_(set_thread_shadow_archreg)(tid, reg, (UInt)UNKNOWN);
2111 Char fbuf[100];
2112 VG_(printf)("f = %#lx\n", f);
2113 VG_(get_fnname)(f, fbuf, 100);
2114 VG_(printf)("name = %s\n", fbuf);
2115 VG_(tool_panic)("argh: clientcall");
2116 }
2117}
2118
2119
2120//zz /*--------------------------------------------------------------------*/
2121//zz /*--- Sanity checking ---*/
2122//zz /*--------------------------------------------------------------------*/
2123//zz
2124//zz /* Check that nobody has spuriously claimed that the first or last 16
2125//zz pages (64 KB) of address space have become accessible. Failure of
2126//zz the following do not per se indicate an internal consistency
2127//zz problem, but they are so likely to that we really want to know
2128//zz about it if so. */
2129//zz Bool pc_replace_cheap_sanity_check) ( void )
2130//zz {
2131//zz if (IS_DISTINGUISHED_SM(primary_map[0])
2132//zz /* kludge: kernel drops a page up at top of address range for
2133//zz magic "optimized syscalls", so we can no longer check the
2134//zz highest page */
2135//zz /* && IS_DISTINGUISHED_SM(primary_map[65535]) */
2136//zz )
2137//zz return True;
2138//zz else
2139//zz return False;
2140//zz }
2141//zz
2142//zz Bool SK_(expensive_sanity_check) ( void )
2143//zz {
2144//zz Int i;
2145//zz
2146//zz /* Make sure nobody changed the distinguished secondary. */
2147//zz for (i = 0; i < SEC_MAP_WORDS; i++)
2148//zz if (distinguished_secondary_map.vseg[i] != UNKNOWN)
2149//zz return False;
2150//zz
2151//zz return True;
2152//zz }
2153
2154
2155/*--------------------------------------------------------------------*/
2156/*--- System calls ---*/
2157/*--------------------------------------------------------------------*/
2158
sewardj1c0ce7a2009-07-01 08:10:49 +00002159void h_pre_syscall ( ThreadId tid, UInt sysno,
2160 UWord* args, UInt nArgs )
sewardj024598e2008-09-18 14:43:05 +00002161{
2162 /* we don't do anything at the pre-syscall point */
2163}
2164
2165/* The post-syscall table is a table of pairs (number, flag).
2166
2167 'flag' is only ever zero or one. If it is zero, it indicates that
2168 default handling for that syscall is required -- namely that the
2169 syscall is deemed to return NONPTR. This is the case for the vast
2170 majority of syscalls. If it is one then some special
2171 syscall-specific handling is is required. No further details of it
2172 are stored in the table.
2173
njnf76d27a2009-05-28 01:53:07 +00002174 On Linux and Darwin, 'number' is a __NR_xxx constant.
sewardj024598e2008-09-18 14:43:05 +00002175
2176 On AIX5, 'number' is an Int*, which points to the Int variable
2177 holding the currently assigned number for this syscall.
2178
2179 When querying the table, we compare the supplied syscall number
njnf76d27a2009-05-28 01:53:07 +00002180 with the 'number' field (directly on Linux and Darwin, after
2181 dereferencing on AIX5), to find the relevant entry. This requires a
2182 linear search of the table. To stop the costs getting too high, the
2183 table is incrementally rearranged after each search, to move commonly
sewardj024598e2008-09-18 14:43:05 +00002184 requested items a bit closer to the front.
2185
2186 The table is built once, the first time it is used. After that we
2187 merely query it (and reorder the entries as a result). */
2188
2189static XArray* /* of UWordPair */ post_syscall_table = NULL;
2190
2191static void setup_post_syscall_table ( void )
2192{
2193 tl_assert(!post_syscall_table);
2194 post_syscall_table = VG_(newXA)( VG_(malloc), "pc.h_main.spst.1",
2195 VG_(free), sizeof(UWordPair) );
2196 tl_assert(post_syscall_table);
2197
2198 /* --------------- LINUX --------------- */
2199
2200# if defined(VGO_linux)
2201
2202# define ADD(_flag, _syscallname) \
2203 do { UWordPair p; p.uw1 = (_syscallname); p.uw2 = (_flag); \
2204 VG_(addToXA)( post_syscall_table, &p ); \
2205 } while (0)
2206
2207 /* These ones definitely don't return pointers. They're not
2208 particularly grammatical, either. */
2209
2210# if defined(__NR__llseek)
2211 ADD(0, __NR__llseek);
2212# endif
2213 ADD(0, __NR__sysctl);
2214# if defined(__NR__newselect)
2215 ADD(0, __NR__newselect);
2216# endif
2217# if defined(__NR_accept)
2218 ADD(0, __NR_accept);
2219# endif
2220 ADD(0, __NR_access);
tom332ffec2009-01-05 12:16:21 +00002221 ADD(0, __NR_alarm);
sewardj024598e2008-09-18 14:43:05 +00002222# if defined(__NR_bind)
2223 ADD(0, __NR_bind);
2224# endif
2225# if defined(__NR_chdir)
2226 ADD(0, __NR_chdir);
2227# endif
2228 ADD(0, __NR_chmod);
2229 ADD(0, __NR_chown);
sewardj41d5dea2009-01-24 10:52:32 +00002230# if defined(__NR_chown32)
2231 ADD(0, __NR_chown32);
2232# endif
sewardj024598e2008-09-18 14:43:05 +00002233 ADD(0, __NR_clock_getres);
2234 ADD(0, __NR_clock_gettime);
2235 ADD(0, __NR_clone);
2236 ADD(0, __NR_close);
2237# if defined(__NR_connect)
2238 ADD(0, __NR_connect);
2239# endif
tom332ffec2009-01-05 12:16:21 +00002240 ADD(0, __NR_creat);
sewardj024598e2008-09-18 14:43:05 +00002241 ADD(0, __NR_dup);
2242 ADD(0, __NR_dup2);
tom9a787f82009-07-27 14:22:25 +00002243 ADD(0, __NR_epoll_create);
sewardj4cb6bf72010-01-01 18:31:41 +00002244# if defined(__NR_epoll_create1)
tom9a787f82009-07-27 14:22:25 +00002245 ADD(0, __NR_epoll_create1);
sewardj4cb6bf72010-01-01 18:31:41 +00002246# endif
tom7ef0d3a2009-10-27 09:31:39 +00002247 ADD(0, __NR_epoll_ctl);
sewardj4cb6bf72010-01-01 18:31:41 +00002248# if defined(__NR_epoll_pwait)
tom7ef0d3a2009-10-27 09:31:39 +00002249 ADD(0, __NR_epoll_pwait);
sewardj4cb6bf72010-01-01 18:31:41 +00002250# endif
tom7ef0d3a2009-10-27 09:31:39 +00002251 ADD(0, __NR_epoll_wait);
sewardj024598e2008-09-18 14:43:05 +00002252 ADD(0, __NR_execve); /* presumably we see this because the call failed? */
2253 ADD(0, __NR_exit); /* hmm, why are we still alive? */
2254 ADD(0, __NR_exit_group);
2255 ADD(0, __NR_fadvise64);
sewardj9f52ee42009-02-23 16:56:15 +00002256 ADD(0, __NR_fallocate);
sewardj024598e2008-09-18 14:43:05 +00002257 ADD(0, __NR_fchmod);
2258 ADD(0, __NR_fchown);
2259# if defined(__NR_fchown32)
2260 ADD(0, __NR_fchown32);
2261# endif
2262 ADD(0, __NR_fcntl);
2263# if defined(__NR_fcntl64)
2264 ADD(0, __NR_fcntl64);
2265# endif
2266 ADD(0, __NR_fdatasync);
sewardj33c57f22009-01-26 00:09:08 +00002267 ADD(0, __NR_flock);
sewardj024598e2008-09-18 14:43:05 +00002268 ADD(0, __NR_fstat);
2269# if defined(__NR_fstat64)
2270 ADD(0, __NR_fstat64);
2271# endif
2272 ADD(0, __NR_fstatfs);
tom065bc7f2009-07-15 16:05:05 +00002273 # if defined(__NR_fstatfs64)
2274 ADD(0, __NR_fstatfs64);
2275# endif
2276 ADD(0, __NR_fsync);
sewardj024598e2008-09-18 14:43:05 +00002277 ADD(0, __NR_ftruncate);
2278# if defined(__NR_ftruncate64)
2279 ADD(0, __NR_ftruncate64);
2280# endif
2281 ADD(0, __NR_futex);
2282 ADD(0, __NR_getcwd);
2283 ADD(0, __NR_getdents); // something to do with teeth
2284 ADD(0, __NR_getdents64);
2285 ADD(0, __NR_getegid);
2286# if defined(__NR_getegid32)
2287 ADD(0, __NR_getegid32);
2288# endif
2289 ADD(0, __NR_geteuid);
2290# if defined(__NR_geteuid32)
2291 ADD(0, __NR_geteuid32);
2292# endif
2293 ADD(0, __NR_getgid);
2294# if defined(__NR_getgid32)
2295 ADD(0, __NR_getgid32);
2296# endif
sewardjad039492009-01-29 08:44:49 +00002297 ADD(0, __NR_getgroups);
tom065bc7f2009-07-15 16:05:05 +00002298# if defined(__NR_getgroups32)
2299 ADD(0, __NR_getgroups32);
2300# endif
sewardj024598e2008-09-18 14:43:05 +00002301 ADD(0, __NR_getitimer);
2302# if defined(__NR_getpeername)
2303 ADD(0, __NR_getpeername);
2304# endif
2305 ADD(0, __NR_getpid);
sewardj7d769112008-10-30 01:44:03 +00002306 ADD(0, __NR_getpgrp);
sewardj024598e2008-09-18 14:43:05 +00002307 ADD(0, __NR_getppid);
tom065bc7f2009-07-15 16:05:05 +00002308 ADD(0, __NR_getpriority);
sewardj024598e2008-09-18 14:43:05 +00002309 ADD(0, __NR_getresgid);
tom065bc7f2009-07-15 16:05:05 +00002310# if defined(__NR_getresgid32)
2311 ADD(0, __NR_getresgid32);
2312# endif
sewardj024598e2008-09-18 14:43:05 +00002313 ADD(0, __NR_getresuid);
sewardj9f52ee42009-02-23 16:56:15 +00002314# if defined(__NR_getresuid32)
2315 ADD(0, __NR_getresuid32);
2316# endif
sewardj024598e2008-09-18 14:43:05 +00002317 ADD(0, __NR_getrlimit);
tom332ffec2009-01-05 12:16:21 +00002318 ADD(0, __NR_getrusage);
sewardj024598e2008-09-18 14:43:05 +00002319# if defined(__NR_getsockname)
2320 ADD(0, __NR_getsockname);
2321# endif
2322# if defined(__NR_getsockopt)
2323 ADD(0, __NR_getsockopt);
2324# endif
sewardj41d5dea2009-01-24 10:52:32 +00002325 ADD(0, __NR_gettid);
sewardj024598e2008-09-18 14:43:05 +00002326 ADD(0, __NR_gettimeofday);
2327 ADD(0, __NR_getuid);
2328# if defined(__NR_getuid32)
2329 ADD(0, __NR_getuid32);
2330# endif
2331 ADD(0, __NR_getxattr);
sewardj738db7b2008-10-20 10:30:08 +00002332 ADD(0, __NR_inotify_add_watch);
sewardj024598e2008-09-18 14:43:05 +00002333 ADD(0, __NR_inotify_init);
sewardje4c3cff2010-02-15 09:58:10 +00002334# if defined(__NR_inotify_init1)
2335 ADD(0, __NR_inotify_init1);
2336# endif
sewardj738db7b2008-10-20 10:30:08 +00002337 ADD(0, __NR_inotify_rm_watch);
sewardj024598e2008-09-18 14:43:05 +00002338 ADD(0, __NR_ioctl); // ioctl -- assuming no pointers returned
sewardj33c57f22009-01-26 00:09:08 +00002339 ADD(0, __NR_ioprio_get);
sewardj024598e2008-09-18 14:43:05 +00002340 ADD(0, __NR_kill);
2341 ADD(0, __NR_link);
2342# if defined(__NR_listen)
2343 ADD(0, __NR_listen);
2344# endif
2345 ADD(0, __NR_lseek);
2346 ADD(0, __NR_lstat);
2347# if defined(__NR_lstat64)
2348 ADD(0, __NR_lstat64);
2349# endif
2350 ADD(0, __NR_madvise);
2351 ADD(0, __NR_mkdir);
sewardj33c57f22009-01-26 00:09:08 +00002352 ADD(0, __NR_mlock);
sewardj024598e2008-09-18 14:43:05 +00002353 ADD(0, __NR_mprotect);
2354 ADD(0, __NR_munmap); // die_mem_munmap already called, segment remove);
sewardj738db7b2008-10-20 10:30:08 +00002355 ADD(0, __NR_nanosleep);
sewardj024598e2008-09-18 14:43:05 +00002356 ADD(0, __NR_open);
tom065bc7f2009-07-15 16:05:05 +00002357 ADD(0, __NR_personality);
sewardj024598e2008-09-18 14:43:05 +00002358 ADD(0, __NR_pipe);
tom0304fa32009-11-03 21:02:16 +00002359# if defined(__NR_pipe2)
2360 ADD(0, __NR_pipe2);
2361# endif
sewardj024598e2008-09-18 14:43:05 +00002362 ADD(0, __NR_poll);
tom065bc7f2009-07-15 16:05:05 +00002363 ADD(0, __NR_prctl);
sewardj024598e2008-09-18 14:43:05 +00002364 ADD(0, __NR_pread64);
2365 ADD(0, __NR_pwrite64);
2366 ADD(0, __NR_read);
2367 ADD(0, __NR_readlink);
2368 ADD(0, __NR_readv);
2369# if defined(__NR_recvfrom)
2370 ADD(0, __NR_recvfrom);
2371# endif
2372# if defined(__NR_recvmsg)
2373 ADD(0, __NR_recvmsg);
2374# endif
2375 ADD(0, __NR_rename);
2376 ADD(0, __NR_rmdir);
2377 ADD(0, __NR_rt_sigaction);
2378 ADD(0, __NR_rt_sigprocmask);
2379 ADD(0, __NR_rt_sigreturn); /* not sure if we should see this or not */
tom065bc7f2009-07-15 16:05:05 +00002380 ADD(0, __NR_rt_sigsuspend);
2381 ADD(0, __NR_rt_sigtimedwait);
sewardj024598e2008-09-18 14:43:05 +00002382 ADD(0, __NR_sched_get_priority_max);
2383 ADD(0, __NR_sched_get_priority_min);
sewardj738db7b2008-10-20 10:30:08 +00002384 ADD(0, __NR_sched_getaffinity);
sewardj024598e2008-09-18 14:43:05 +00002385 ADD(0, __NR_sched_getparam);
2386 ADD(0, __NR_sched_getscheduler);
sewardj41d5dea2009-01-24 10:52:32 +00002387 ADD(0, __NR_sched_setaffinity);
sewardj024598e2008-09-18 14:43:05 +00002388 ADD(0, __NR_sched_setscheduler);
2389 ADD(0, __NR_sched_yield);
2390 ADD(0, __NR_select);
sewardj33c57f22009-01-26 00:09:08 +00002391# if defined(__NR_semctl)
2392 ADD(0, __NR_semctl);
2393# endif
2394# if defined(__NR_semget)
2395 ADD(0, __NR_semget);
2396# endif
2397# if defined(__NR_semop)
2398 ADD(0, __NR_semop);
2399# endif
sewardj024598e2008-09-18 14:43:05 +00002400# if defined(__NR_sendto)
2401 ADD(0, __NR_sendto);
2402# endif
tom332ffec2009-01-05 12:16:21 +00002403# if defined(__NR_sendmsg)
2404 ADD(0, __NR_sendmsg);
2405# endif
sewardj024598e2008-09-18 14:43:05 +00002406 ADD(0, __NR_set_robust_list);
2407# if defined(__NR_set_thread_area)
2408 ADD(0, __NR_set_thread_area);
2409# endif
2410 ADD(0, __NR_set_tid_address);
sewardjad039492009-01-29 08:44:49 +00002411 ADD(0, __NR_setfsgid);
2412 ADD(0, __NR_setfsuid);
2413 ADD(0, __NR_setgid);
sewardj024598e2008-09-18 14:43:05 +00002414 ADD(0, __NR_setitimer);
sewardj7d769112008-10-30 01:44:03 +00002415 ADD(0, __NR_setpgid);
tom065bc7f2009-07-15 16:05:05 +00002416 ADD(0, __NR_setpriority);
tom5012e9f2009-07-16 08:47:08 +00002417 ADD(0, __NR_setregid);
sewardjad039492009-01-29 08:44:49 +00002418 ADD(0, __NR_setresgid);
tom5012e9f2009-07-16 08:47:08 +00002419 ADD(0, __NR_setresuid);
2420 ADD(0, __NR_setreuid);
sewardj024598e2008-09-18 14:43:05 +00002421 ADD(0, __NR_setrlimit);
2422 ADD(0, __NR_setsid);
2423# if defined(__NR_setsockopt)
2424 ADD(0, __NR_setsockopt);
2425# endif
sewardjad039492009-01-29 08:44:49 +00002426 ADD(0, __NR_setuid);
sewardj024598e2008-09-18 14:43:05 +00002427# if defined(__NR_shmctl)
2428 ADD(0, __NR_shmctl);
2429 ADD(0, __NR_shmdt);
2430# endif
2431# if defined(__NR_shutdown)
2432 ADD(0, __NR_shutdown);
2433# endif
sewardj41d5dea2009-01-24 10:52:32 +00002434 ADD(0, __NR_sigaltstack);
sewardj024598e2008-09-18 14:43:05 +00002435# if defined(__NR_socket)
2436 ADD(0, __NR_socket);
2437# endif
2438# if defined(__NR_socketcall)
2439 ADD(0, __NR_socketcall); /* the nasty x86-linux socket multiplexor */
2440# endif
sewardj23e8a292009-01-07 09:35:10 +00002441# if defined(__NR_socketpair)
2442 ADD(0, __NR_socketpair);
2443# endif
sewardj024598e2008-09-18 14:43:05 +00002444# if defined(__NR_statfs64)
2445 ADD(0, __NR_statfs64);
2446# endif
2447# if defined(__NR_sigreturn)
2448 ADD(0, __NR_sigreturn); /* not sure if we should see this or not */
2449# endif
2450# if defined(__NR_stat64)
2451 ADD(0, __NR_stat64);
2452# endif
2453 ADD(0, __NR_stat);
2454 ADD(0, __NR_statfs);
2455 ADD(0, __NR_symlink);
2456 ADD(0, __NR_sysinfo);
2457 ADD(0, __NR_tgkill);
2458 ADD(0, __NR_time);
2459 ADD(0, __NR_times);
2460 ADD(0, __NR_truncate);
2461# if defined(__NR_truncate64)
2462 ADD(0, __NR_truncate64);
2463# endif
2464# if defined(__NR_ugetrlimit)
2465 ADD(0, __NR_ugetrlimit);
2466# endif
2467 ADD(0, __NR_umask);
2468 ADD(0, __NR_uname);
2469 ADD(0, __NR_unlink);
2470 ADD(0, __NR_utime);
tom065bc7f2009-07-15 16:05:05 +00002471 ADD(0, __NR_vfork);
sewardj024598e2008-09-18 14:43:05 +00002472# if defined(__NR_waitpid)
2473 ADD(0, __NR_waitpid);
2474# endif
2475 ADD(0, __NR_wait4);
2476 ADD(0, __NR_write);
2477 ADD(0, __NR_writev);
2478
2479 /* Whereas the following need special treatment */
2480# if defined(__NR_arch_prctl)
2481 ADD(1, __NR_arch_prctl);
2482# endif
2483 ADD(1, __NR_brk);
2484 ADD(1, __NR_mmap);
2485# if defined(__NR_mmap2)
2486 ADD(1, __NR_mmap2);
2487# endif
2488# if defined(__NR_shmat)
2489 ADD(1, __NR_shmat);
2490# endif
2491# if defined(__NR_shmget)
2492 ADD(1, __NR_shmget);
2493# endif
sewardj1c0ce7a2009-07-01 08:10:49 +00002494# if defined(__NR_ipc) && defined(VKI_SHMAT)
2495 ADD(1, __NR_ipc); /* ppc{32,64}-linux horrors */
2496# endif
sewardj024598e2008-09-18 14:43:05 +00002497
2498 /* --------------- AIX5 --------------- */
2499
2500# elif defined(VGO_aix5)
2501
2502# define ADD(_flag, _syscallname) \
2503 do { \
2504 UWordPair p; \
2505 if ((_syscallname) != __NR_AIX5_UNKNOWN) { \
2506 p.uw1 = (UWord)&(_syscallname); p.uw2 = (_flag); \
2507 VG_(addToXA)( post_syscall_table, &p ); \
2508 } \
2509 } while (0)
2510
2511 /* Just a minimal set of handlers, enough to make
2512 a 32- and 64-bit hello-world program run. */
2513 ADD(1, __NR_AIX5___loadx); /* not sure what to do here */
2514 ADD(0, __NR_AIX5__exit);
2515 ADD(0, __NR_AIX5_access);
2516 ADD(0, __NR_AIX5_getgidx);
2517 ADD(0, __NR_AIX5_getuidx);
2518 ADD(0, __NR_AIX5_kfcntl);
2519 ADD(0, __NR_AIX5_kioctl);
2520 ADD(1, __NR_AIX5_kload); /* not sure what to do here */
2521 ADD(0, __NR_AIX5_kwrite);
2522
njnf76d27a2009-05-28 01:53:07 +00002523 /* --------------- DARWIN ------------- */
2524
2525# elif defined(VGO_darwin)
2526
2527# define ADD(_flag, _syscallname) \
2528 do { UWordPair p; p.uw1 = (_syscallname); p.uw2 = (_flag); \
2529 VG_(addToXA)( post_syscall_table, &p ); \
2530 } while (0)
2531
2532 // DDD: a desultory attempt thus far...
2533
2534 // Unix/BSD syscalls.
2535
2536 // Mach traps.
2537 ADD(0, __NR_host_self_trap);
2538 ADD(0, __NR_mach_msg_trap);
2539 ADD(0, __NR_mach_reply_port);
2540 ADD(0, __NR_task_self_trap);
2541
2542 // Machine-dependent syscalls.
njn4e8808b2009-06-05 01:33:16 +00002543 ADD(0, __NR_thread_fast_set_cthread_self);
njnf76d27a2009-05-28 01:53:07 +00002544
2545 /* ------------------------------------ */
2546
sewardj024598e2008-09-18 14:43:05 +00002547# else
2548# error "Unsupported OS"
2549# endif
2550
2551# undef ADD
2552}
2553
2554
sewardj1c0ce7a2009-07-01 08:10:49 +00002555void h_post_syscall ( ThreadId tid, UInt sysno,
2556 UWord* args, UInt nArgs, SysRes res )
sewardj024598e2008-09-18 14:43:05 +00002557{
2558 Word i, n;
2559 UWordPair* pair;
2560
2561 if (!post_syscall_table)
2562 setup_post_syscall_table();
2563
2564 /* search for 'sysno' in the post_syscall_table */
2565 n = VG_(sizeXA)( post_syscall_table );
2566 for (i = 0; i < n; i++) {
2567 pair = VG_(indexXA)( post_syscall_table, i );
njnf76d27a2009-05-28 01:53:07 +00002568# if defined(VGO_linux) || defined(VGO_darwin)
sewardj024598e2008-09-18 14:43:05 +00002569 if (pair->uw1 == (UWord)sysno)
2570 break;
2571# elif defined(VGO_aix5)
2572 if (*(Int*)(pair->uw1) == (Int)sysno)
2573 break;
2574# else
2575# error "Unsupported OS"
2576# endif
2577 }
2578
2579 tl_assert(i >= 0 && i <= n);
2580
2581 if (i == n) {
njn1a1e95c2009-06-03 06:50:06 +00002582 VG_(printf)("sysno == %s", VG_SYSNUM_STRING_EXTRA(sysno));
sewardj024598e2008-09-18 14:43:05 +00002583 VG_(tool_panic)("unhandled syscall");
2584 }
2585
2586 /* So we found the relevant entry. Move it one step
2587 forward so as to speed future accesses to it. */
2588 if (i > 0) {
2589 UWordPair tmp, *p, *q;
2590 p = VG_(indexXA)( post_syscall_table, i-1 );
2591 q = VG_(indexXA)( post_syscall_table, i-0 );
2592 tmp = *p;
2593 *p = *q;
2594 *q = tmp;
2595 i--;
2596 }
2597
2598 /* Deal with the common case */
2599 pair = VG_(indexXA)( post_syscall_table, i );
sewardj1c0ce7a2009-07-01 08:10:49 +00002600 if (pair->uw2 == 0)
2601 /* the common case */
2602 goto res_NONPTR_err_NONPTR;
sewardj024598e2008-09-18 14:43:05 +00002603
2604 /* Special handling for all remaining cases */
2605 tl_assert(pair->uw2 == 1);
2606
2607# if defined(__NR_arch_prctl)
2608 if (sysno == __NR_arch_prctl) {
2609 /* This is nasty. On amd64-linux, arch_prctl may write a
2610 value to guest_FS_ZERO, and we need to shadow that value.
2611 Hence apply nonptr_or_unknown to it here, after the
2612 syscall completes. */
2613 post_reg_write_nonptr_or_unknown( tid, PC_OFF_FS_ZERO,
2614 PC_SZB_FS_ZERO );
sewardj1c0ce7a2009-07-01 08:10:49 +00002615 goto res_NONPTR_err_NONPTR;
sewardj024598e2008-09-18 14:43:05 +00002616 }
2617# endif
2618
2619# if defined(__NR_brk)
2620 // With brk(), result (of kernel syscall, not glibc wrapper) is a heap
2621 // pointer. Make the shadow UNKNOWN.
sewardj1c0ce7a2009-07-01 08:10:49 +00002622 if (sysno == __NR_brk)
2623 goto res_UNKNOWN_err_NONPTR;
sewardj024598e2008-09-18 14:43:05 +00002624# endif
2625
2626 // With mmap, new_mem_mmap() has already been called and added the
2627 // segment (we did it there because we had the result address and size
2628 // handy). So just set the return value shadow.
2629 if (sysno == __NR_mmap
2630# if defined(__NR_mmap2)
2631 || sysno == __NR_mmap2
2632# endif
2633# if defined(__NR_AIX5___loadx)
2634 || (sysno == __NR_AIX5___loadx && __NR_AIX5___loadx != __NR_AIX5_UNKNOWN)
2635# endif
2636# if defined(__NR_AIX5_kload)
2637 || (sysno == __NR_AIX5_kload && __NR_AIX5_kload != __NR_AIX5_UNKNOWN)
2638# endif
2639 ) {
njncda2f0f2009-05-18 02:12:08 +00002640 if (sr_isError(res)) {
sewardj024598e2008-09-18 14:43:05 +00002641 // mmap() had an error, return value is a small negative integer
sewardj1c0ce7a2009-07-01 08:10:49 +00002642 goto res_NONPTR_err_NONPTR;
sewardj024598e2008-09-18 14:43:05 +00002643 } else {
sewardj1c0ce7a2009-07-01 08:10:49 +00002644 goto res_UNKNOWN_err_NONPTR;
sewardj024598e2008-09-18 14:43:05 +00002645 }
2646 return;
2647 }
2648
2649 // shmat uses the same scheme. We will just have had a
2650 // notification via new_mem_mmap. Just set the return value shadow.
2651# if defined(__NR_shmat)
2652 if (sysno == __NR_shmat) {
njncda2f0f2009-05-18 02:12:08 +00002653 if (sr_isError(res)) {
sewardj1c0ce7a2009-07-01 08:10:49 +00002654 goto res_NONPTR_err_NONPTR;
sewardj024598e2008-09-18 14:43:05 +00002655 } else {
sewardj1c0ce7a2009-07-01 08:10:49 +00002656 goto res_UNKNOWN_err_NONPTR;
sewardj024598e2008-09-18 14:43:05 +00002657 }
sewardj024598e2008-09-18 14:43:05 +00002658 }
2659# endif
2660
2661# if defined(__NR_shmget)
sewardj1c0ce7a2009-07-01 08:10:49 +00002662 if (sysno == __NR_shmget)
sewardj024598e2008-09-18 14:43:05 +00002663 // FIXME: is this correct?
sewardj1c0ce7a2009-07-01 08:10:49 +00002664 goto res_UNKNOWN_err_NONPTR;
2665# endif
2666
2667# if defined(__NR_ipc) && defined(VKI_SHMAT)
2668 /* perhaps this should be further conditionalised with
2669 && (defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
2670 Note, this just copies the behaviour of __NR_shmget above.
2671
2672 JRS 2009 June 02: it seems that the return value from
2673 sys_ipc(VKI_SHMAT, ...) doesn't have much relationship to the
2674 result returned by the originating user-level shmat call. It's
2675 different (and much lower) by a large but integral number of
2676 pages. I don't have time to chase this right now. Observed on
2677 ppc{32,64}-linux. Result appears to be false errors from apps
2678 using shmat. Confusion though -- shouldn't be related to the
2679 actual numeric values returned by the syscall, though, should
2680 it? Confused. Maybe some bad interaction with a
2681 nonpointer-or-unknown heuristic? */
2682 if (sysno == __NR_ipc) {
2683 if (args[0] == VKI_SHMAT) {
2684 goto res_UNKNOWN_err_NONPTR;
2685 } else {
2686 goto res_NONPTR_err_NONPTR;
2687 }
sewardj024598e2008-09-18 14:43:05 +00002688 }
2689# endif
2690
2691 /* If we get here, it implies the corresponding entry in
2692 post_syscall_table has .w2 == 1, which in turn implies there
2693 should be special-case code for it above. */
2694 tl_assert(0);
sewardj1c0ce7a2009-07-01 08:10:49 +00002695
2696 res_NONPTR_err_NONPTR:
2697 VG_(set_syscall_return_shadows)( tid, /* retval */ (UWord)NONPTR, 0,
2698 /* error */ (UWord)NONPTR, 0 );
2699 return;
2700
2701 res_UNKNOWN_err_NONPTR:
2702 VG_(set_syscall_return_shadows)( tid, /* retval */ (UWord)UNKNOWN, 0,
2703 /* error */ (UWord)NONPTR, 0 );
2704 return;
sewardj024598e2008-09-18 14:43:05 +00002705}
2706
2707
2708/*--------------------------------------------------------------------*/
2709/*--- Functions called from generated code ---*/
2710/*--------------------------------------------------------------------*/
2711
2712#if SC_SEGS
2713static void checkSeg ( Seg vseg ) {
2714 tl_assert(vseg == UNKNOWN || vseg == NONPTR || vseg == BOTTOM
2715 || Seg__plausible(vseg) );
2716}
2717#endif
2718
2719// XXX: could be more sophisticated -- actually track the lowest/highest
2720// valid address used by the program, and then return False for anything
2721// below that (using a suitable safety margin). Also, nothing above
2722// 0xc0000000 is valid [unless you've changed that in your kernel]
2723static inline Bool looks_like_a_pointer(Addr a)
2724{
2725# if defined(VGA_x86) || defined(VGA_ppc32)
2726 tl_assert(sizeof(UWord) == 4);
2727 return (a > 0x01000000UL && a < 0xFF000000UL);
sewardj4cb6bf72010-01-01 18:31:41 +00002728
sewardj024598e2008-09-18 14:43:05 +00002729# elif defined(VGA_amd64) || defined(VGA_ppc64)
2730 tl_assert(sizeof(UWord) == 8);
2731 return (a >= 16 * 0x10000UL && a < 0xFF00000000000000UL);
sewardj4cb6bf72010-01-01 18:31:41 +00002732
2733# elif defined(VGA_arm)
2734 /* Unfortunately arm-linux seems to load the exe at very low, at
2735 0x8000, so we have to assume any value above that is a pointer,
2736 which is pretty dismal. */
2737 tl_assert(sizeof(UWord) == 4);
2738 return (a >= 0x00008000UL && a < 0xFF000000UL);
2739
sewardj024598e2008-09-18 14:43:05 +00002740# else
2741# error "Unsupported architecture"
2742# endif
2743}
2744
2745static inline VG_REGPARM(1)
2746Seg* nonptr_or_unknown(UWord x)
2747{
2748 Seg* res = looks_like_a_pointer(x) ? UNKNOWN : NONPTR;
2749 if (0) VG_(printf)("nonptr_or_unknown %s %#lx\n",
2750 res==UNKNOWN ? "UUU" : "nnn", x);
2751 return res;
2752}
2753
2754//zz static __attribute__((regparm(1)))
2755//zz void print_BB_entry(UInt bb)
2756//zz {
2757//zz VG_(printf)("%u =\n", bb);
2758//zz }
2759
sewardj59347ff2008-12-23 02:31:22 +00002760//static ULong stats__tot_mem_refs = 0;
2761//static ULong stats__refs_in_a_seg = 0;
2762//static ULong stats__refs_lost_seg = 0;
sewardj024598e2008-09-18 14:43:05 +00002763
2764typedef
2765 struct { ExeContext* ec; UWord count; }
2766 Lossage;
2767
2768static OSet* lossage = NULL;
2769
sewardj59347ff2008-12-23 02:31:22 +00002770//static void inc_lossage ( ExeContext* ec )
2771//{
2772// Lossage key, *res, *nyu;
2773// key.ec = ec;
2774// key.count = 0; /* frivolous */
2775// res = VG_(OSetGen_Lookup)(lossage, &key);
2776// if (res) {
2777// tl_assert(res->ec == ec);
2778// res->count++;
2779// } else {
2780// nyu = (Lossage*)VG_(OSetGen_AllocNode)(lossage, sizeof(Lossage));
2781// tl_assert(nyu);
2782// nyu->ec = ec;
2783// nyu->count = 1;
2784// VG_(OSetGen_Insert)( lossage, nyu );
2785// }
2786//}
sewardj024598e2008-09-18 14:43:05 +00002787
2788static void init_lossage ( void )
2789{
2790 lossage = VG_(OSetGen_Create)( /*keyOff*/ offsetof(Lossage,ec),
2791 /*fastCmp*/NULL,
2792 VG_(malloc), "pc.h_main.il.1",
2793 VG_(free) );
2794 tl_assert(lossage);
2795}
2796
sewardj59347ff2008-12-23 02:31:22 +00002797//static void show_lossage ( void )
2798//{
2799// Lossage* elem;
2800// VG_(OSetGen_ResetIter)( lossage );
2801// while ( (elem = VG_(OSetGen_Next)(lossage)) ) {
2802// if (elem->count < 10) continue;
2803// //Char buf[100];
2804// //(void)VG_(describe_IP)(elem->ec, buf, sizeof(buf)-1);
2805// //buf[sizeof(buf)-1] = 0;
2806// //VG_(printf)(" %,8lu %s\n", elem->count, buf);
2807// VG_(message)(Vg_UserMsg, "Lossage count %'lu at", elem->count);
2808// VG_(pp_ExeContext)(elem->ec);
2809// }
2810//}
sewardj024598e2008-09-18 14:43:05 +00002811
2812// This function is called *a lot*; inlining it sped up Konqueror by 20%.
2813static inline
2814void check_load_or_store(Bool is_write, Addr m, UWord sz, Seg* mptr_vseg)
2815{
sewardj024598e2008-09-18 14:43:05 +00002816#if 0
sewardj4815eb52008-10-20 23:33:49 +00002817 tl_assert(0);
2818 if (h_clo_lossage_check) {
sewardj024598e2008-09-18 14:43:05 +00002819 Seg* seg;
2820 stats__tot_mem_refs++;
2821 if (ISList__findI0( seglist, (Addr)m, &seg )) {
2822 /* m falls inside 'seg' (that is, we are making a memory
2823 reference inside 'seg'). Now, really mptr_vseg should be
2824 a tracked segment of some description. Badness is when
2825 mptr_vseg is UNKNOWN, BOTTOM or NONPTR at this point,
2826 since that means we've lost the type of it somehow: it
2827 shoud say that m points into a real segment (preferable
2828 'seg'), but it doesn't. */
2829 if (Seg__status_is_SegHeap(seg)) {
2830 stats__refs_in_a_seg++;
2831 if (UNKNOWN == mptr_vseg
2832 || BOTTOM == mptr_vseg || NONPTR == mptr_vseg) {
2833 ExeContext* ec;
2834 Char buf[100];
2835 static UWord xx = 0;
2836 stats__refs_lost_seg++;
2837 ec = VG_(record_ExeContext)( VG_(get_running_tid)(), 0 );
2838 inc_lossage(ec);
2839 if (0) {
2840 VG_(message)(Vg_DebugMsg, "");
2841 VG_(message)(Vg_DebugMsg,
2842 "Lossage %s %#lx sz %lu inside block alloc'd",
2843 is_write ? "wr" : "rd", m, (UWord)sz);
2844 VG_(pp_ExeContext)(Seg__where(seg));
2845 }
2846 if (xx++ < 0) {
2847 Addr ip = VG_(get_IP)( VG_(get_running_tid)() );
2848 (void)VG_(describe_IP)( ip, buf, sizeof(buf)-1);
2849 buf[sizeof(buf)-1] = 0;
2850 VG_(printf)("lossage at %p %s\n", ec, buf );
2851 }
2852 }
2853 }
2854 }
sewardj024598e2008-09-18 14:43:05 +00002855 } /* clo_lossage_check */
sewardj4815eb52008-10-20 23:33:49 +00002856#endif
sewardj024598e2008-09-18 14:43:05 +00002857
2858# if SC_SEGS
2859 checkSeg(mptr_vseg);
2860# endif
2861
2862 if (UNKNOWN == mptr_vseg) {
2863 // do nothing
2864
2865 } else if (BOTTOM == mptr_vseg) {
2866 // do nothing
2867
2868 } else if (NONPTR == mptr_vseg) {
2869 h_record_heap_error( m, sz, mptr_vseg, is_write );
2870
2871 } else {
2872 // check all segment ranges in the circle
2873 // if none match, warn about 1st seg
2874 // else, check matching one isn't freed
2875 Bool is_ok = False;
2876 Seg* curr = mptr_vseg;
2877 Addr mhi;
2878
2879 // Accesses partly outside range are an error, unless it's an aligned
2880 // word-sized read, and --partial-loads-ok=yes. This is to cope with
2881 // gcc's/glibc's habits of doing word-sized accesses that read past
2882 // the ends of arrays/strings.
2883 // JRS 2008-sept-11: couldn't this be moved off the critical path?
2884 if (!is_write && sz == sizeof(UWord)
2885 && h_clo_partial_loads_ok && SHMEM_IS_WORD_ALIGNED(m)) {
2886 mhi = m;
2887 } else {
2888 mhi = m+sz-1;
2889 }
2890
2891 if (0) VG_(printf)("calling seg_ci %p %#lx %#lx\n", curr,m,mhi);
2892 is_ok = curr->addr <= m && mhi < curr->addr + curr->szB;
2893
2894 // If it's an overrun/underrun of a freed block, don't give both
2895 // warnings, since the first one mentions that the block has been
2896 // freed.
2897 if ( ! is_ok || Seg__is_freed(curr) )
2898 h_record_heap_error( m, sz, mptr_vseg, is_write );
2899 }
2900}
2901
2902// ------------------ Load handlers ------------------ //
2903
2904/* On 32 bit targets, we will use:
2905 check_load1 check_load2 check_load4_P
2906 check_load4 (for 32-bit FP reads)
2907 check_load8 (for 64-bit FP reads)
2908 check_load16 (for xmm/altivec reads)
2909 On 64 bit targets, we will use:
2910 check_load1 check_load2 check_load4 check_load8_P
2911 check_load8 (for 64-bit FP reads)
2912 check_load16 (for xmm/altivec reads)
2913
2914 A "_P" handler reads a pointer from memory, and so returns a value
2915 to the generated code -- the pointer's shadow value. That implies
2916 that check_load4_P is only to be called on a 32 bit host and
2917 check_load8_P is only to be called on a 64 bit host. For all other
2918 cases no shadow value is returned; we merely check that the pointer
2919 (m) matches the block described by its shadow value (mptr_vseg).
2920*/
2921
2922// This handles 128 bit loads on both 32 bit and 64 bit targets.
2923static VG_REGPARM(2)
2924void check_load16(Addr m, Seg* mptr_vseg)
2925{
2926# if SC_SEGS
2927 checkSeg(mptr_vseg);
2928# endif
2929 check_load_or_store(/*is_write*/False, m, 16, mptr_vseg);
2930}
2931
2932// This handles 64 bit FP-or-otherwise-nonpointer loads on both
2933// 32 bit and 64 bit targets.
2934static VG_REGPARM(2)
2935void check_load8(Addr m, Seg* mptr_vseg)
2936{
2937# if SC_SEGS
2938 checkSeg(mptr_vseg);
2939# endif
2940 check_load_or_store(/*is_write*/False, m, 8, mptr_vseg);
2941}
2942
2943// This handles 64 bit loads on 64 bit targets. It must
2944// not be called on 32 bit targets.
2945// return m.vseg
2946static VG_REGPARM(2)
2947Seg* check_load8_P(Addr m, Seg* mptr_vseg)
2948{
2949 Seg* vseg;
2950 tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */
2951# if SC_SEGS
2952 checkSeg(mptr_vseg);
2953# endif
2954 check_load_or_store(/*is_write*/False, m, 8, mptr_vseg);
2955 if (VG_IS_8_ALIGNED(m)) {
2956 vseg = get_mem_vseg(m);
2957 } else {
2958 vseg = nonptr_or_unknown( *(ULong*)m );
2959 }
2960 return vseg;
2961}
2962
2963// This handles 32 bit loads on 32 bit targets. It must
2964// not be called on 64 bit targets.
2965// return m.vseg
2966static VG_REGPARM(2)
2967Seg* check_load4_P(Addr m, Seg* mptr_vseg)
2968{
2969 Seg* vseg;
2970 tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */
2971# if SC_SEGS
2972 checkSeg(mptr_vseg);
2973# endif
2974 check_load_or_store(/*is_write*/False, m, 4, mptr_vseg);
2975 if (VG_IS_4_ALIGNED(m)) {
2976 vseg = get_mem_vseg(m);
2977 } else {
2978 vseg = nonptr_or_unknown( *(UInt*)m );
2979 }
2980 return vseg;
2981}
2982
2983// Used for both 32 bit and 64 bit targets.
2984static VG_REGPARM(2)
2985void check_load4(Addr m, Seg* mptr_vseg)
2986{
2987# if SC_SEGS
2988 checkSeg(mptr_vseg);
2989# endif
2990 check_load_or_store(/*is_write*/False, m, 4, mptr_vseg);
2991}
2992
2993// Used for both 32 bit and 64 bit targets.
2994static VG_REGPARM(2)
2995void check_load2(Addr m, Seg* mptr_vseg)
2996{
2997# if SC_SEGS
2998 checkSeg(mptr_vseg);
2999# endif
3000 check_load_or_store(/*is_write*/False, m, 2, mptr_vseg);
3001}
3002
3003// Used for both 32 bit and 64 bit targets.
3004static VG_REGPARM(2)
3005void check_load1(Addr m, Seg* mptr_vseg)
3006{
3007# if SC_SEGS
3008 checkSeg(mptr_vseg);
3009# endif
3010 check_load_or_store(/*is_write*/False, m, 1, mptr_vseg);
3011}
3012
3013// ------------------ Store handlers ------------------ //
3014
3015/* On 32 bit targets, we will use:
sewardj1c0ce7a2009-07-01 08:10:49 +00003016 check_store1 check_store2 check_store4_P check_store4C_P
sewardj024598e2008-09-18 14:43:05 +00003017 check_store4 (for 32-bit nonpointer stores)
3018 check_store8_ms4B_ls4B (for 64-bit stores)
3019 check_store16_ms4B_4B_4B_ls4B (for xmm/altivec stores)
3020
3021 On 64 bit targets, we will use:
sewardj1c0ce7a2009-07-01 08:10:49 +00003022 check_store1 check_store2 check_store4 check_store4C
3023 check_store8_P check_store_8C_P
sewardj024598e2008-09-18 14:43:05 +00003024 check_store8_all8B (for 64-bit nonpointer stores)
3025 check_store16_ms8B_ls8B (for xmm/altivec stores)
3026
3027 A "_P" handler writes a pointer to memory, and so has an extra
3028 argument -- the pointer's shadow value. That implies that
sewardj1c0ce7a2009-07-01 08:10:49 +00003029 check_store4{,C}_P is only to be called on a 32 bit host and
3030 check_store8{,C}_P is only to be called on a 64 bit host. For all
sewardj024598e2008-09-18 14:43:05 +00003031 other cases, and for the misaligned _P cases, the strategy is to
3032 let the store go through, and then snoop around with
3033 nonptr_or_unknown to fix up the shadow values of any affected
3034 words. */
3035
sewardj1c0ce7a2009-07-01 08:10:49 +00003036/* Helpers for store-conditionals. Ugly kludge :-(
3037 They all return 1 if the SC was successful and 0 if it failed. */
3038static inline UWord do_store_conditional_32( Addr m/*dst*/, UInt t/*val*/ )
3039{
3040# if defined(VGA_ppc32) || defined(VGA_ppc64)
3041 UWord success;
3042 /* If this assertion fails, the underlying IR is (semantically) ill-formed
3043 as per the IR spec for IRStmt_Store. */
3044 tl_assert(VG_IS_4_ALIGNED(m));
3045 __asm__ __volatile__(
3046 "stwcx. %2,0,%1" "\n\t" /* data,0,addr */
3047 "mfcr %0" "\n\t"
3048 "srwi %0,%0,29" "\n\t" /* move relevant CR bit to LSB */
3049 : /*out*/"=b"(success)
3050 : /*in*/ "b"(m), "b"( (UWord)t )
3051 : /*trash*/ "memory", "cc"
3052 /* Note: srwi is OK even on 64-bit host because the we're
3053 after bit 29 (normal numbering) and we mask off all the
3054 other junk just below. */
3055 );
3056 return success & (UWord)1;
3057# else
3058 tl_assert(0); /* not implemented on other platforms */
3059# endif
3060}
3061
3062static inline UWord do_store_conditional_64( Addr m/*dst*/, ULong t/*val*/ )
3063{
3064# if defined(VGA_ppc64)
3065 UWord success;
3066 /* If this assertion fails, the underlying IR is (semantically) ill-formed
3067 as per the IR spec for IRStmt_Store. */
3068 tl_assert(VG_IS_8_ALIGNED(m));
3069 __asm__ __volatile__(
3070 "stdcx. %2,0,%1" "\n\t" /* data,0,addr */
3071 "mfcr %0" "\n\t"
3072 "srdi %0,%0,29" "\n\t" /* move relevant CR bit to LSB */
3073 : /*out*/"=b"(success)
3074 : /*in*/ "b"(m), "b"( (UWord)t )
3075 : /*trash*/ "memory", "cc"
3076 );
3077 return success & (UWord)1;
3078# else
3079 tl_assert(0); /* not implemented on other platforms */
3080# endif
3081}
3082
sewardj024598e2008-09-18 14:43:05 +00003083/* Apply nonptr_or_unknown to all the words intersecting
3084 [a, a+len). */
sewardj2d630e22009-07-09 10:52:03 +00003085static inline VG_REGPARM(2)
sewardj024598e2008-09-18 14:43:05 +00003086void nonptr_or_unknown_range ( Addr a, SizeT len )
3087{
3088 const SizeT wszB = sizeof(UWord);
3089 Addr wfirst = VG_ROUNDDN(a, wszB);
3090 Addr wlast = VG_ROUNDDN(a+len-1, wszB);
3091 Addr a2;
3092 tl_assert(wfirst <= wlast);
3093 for (a2 = wfirst ; a2 <= wlast; a2 += wszB) {
3094 set_mem_vseg( a2, nonptr_or_unknown( *(UWord*)a2 ));
3095 }
3096}
3097
sewardj2d630e22009-07-09 10:52:03 +00003098// Write to shadow memory, for a 32-bit store. Must only
3099// be used on 32-bit targets.
3100static inline VG_REGPARM(2)
3101void do_shadow_store4_P( Addr m, Seg* vseg )
3102{
3103 tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */
3104 if (VG_IS_4_ALIGNED(m)) {
3105 set_mem_vseg( m, vseg );
3106 } else {
3107 // straddling two words
3108 nonptr_or_unknown_range(m, 4);
3109 }
3110}
3111
3112// Write to shadow memory, for a 64-bit store. Must only
3113// be used on 64-bit targets.
3114static inline VG_REGPARM(2)
3115void do_shadow_store8_P( Addr m, Seg* vseg )
3116{
3117 tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */
3118 if (VG_IS_8_ALIGNED(m)) {
3119 set_mem_vseg( m, vseg );
3120 } else {
3121 // straddling two words
3122 nonptr_or_unknown_range(m, 8);
3123 }
3124}
3125
sewardj024598e2008-09-18 14:43:05 +00003126// This handles 128 bit stores on 64 bit targets. The
3127// store data is passed in 2 pieces, the most significant
3128// bits first.
3129static VG_REGPARM(3)
3130void check_store16_ms8B_ls8B(Addr m, Seg* mptr_vseg,
3131 UWord ms8B, UWord ls8B)
3132{
3133 tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */
3134# if SC_SEGS
3135 checkSeg(mptr_vseg);
3136# endif
3137 check_load_or_store(/*is_write*/True, m, 16, mptr_vseg);
3138 // Actually *do* the STORE here
3139 if (host_is_little_endian()) {
3140 // FIXME: aren't we really concerned whether the guest
3141 // is little endian, not whether the host is?
3142 *(ULong*)(m + 0) = ls8B;
3143 *(ULong*)(m + 8) = ms8B;
3144 } else {
3145 *(ULong*)(m + 0) = ms8B;
3146 *(ULong*)(m + 8) = ls8B;
3147 }
3148 nonptr_or_unknown_range(m, 16);
3149}
3150
3151// This handles 128 bit stores on 64 bit targets. The
3152// store data is passed in 2 pieces, the most significant
3153// bits first.
3154static VG_REGPARM(3)
3155void check_store16_ms4B_4B_4B_ls4B(Addr m, Seg* mptr_vseg,
3156 UWord ms4B, UWord w2,
3157 UWord w1, UWord ls4B)
3158{
3159 tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */
3160# if SC_SEGS
3161 checkSeg(mptr_vseg);
3162# endif
3163 check_load_or_store(/*is_write*/True, m, 16, mptr_vseg);
3164 // Actually *do* the STORE here
3165 if (host_is_little_endian()) {
3166 // FIXME: aren't we really concerned whether the guest
3167 // is little endian, not whether the host is?
3168 *(UInt*)(m + 0) = ls4B;
3169 *(UInt*)(m + 4) = w1;
3170 *(UInt*)(m + 8) = w2;
3171 *(UInt*)(m + 12) = ms4B;
3172 } else {
3173 *(UInt*)(m + 0) = ms4B;
3174 *(UInt*)(m + 4) = w2;
3175 *(UInt*)(m + 8) = w1;
3176 *(UInt*)(m + 12) = ls4B;
3177 }
3178 nonptr_or_unknown_range(m, 16);
3179}
3180
3181// This handles 64 bit stores on 32 bit targets. The
3182// store data is passed in 2 pieces, the most significant
3183// bits first.
3184static VG_REGPARM(3)
3185void check_store8_ms4B_ls4B(Addr m, Seg* mptr_vseg,
3186 UWord ms4B, UWord ls4B)
3187{
3188 tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */
3189# if SC_SEGS
3190 checkSeg(mptr_vseg);
3191# endif
3192 check_load_or_store(/*is_write*/True, m, 8, mptr_vseg);
3193 // Actually *do* the STORE here
3194 if (host_is_little_endian()) {
3195 // FIXME: aren't we really concerned whether the guest
3196 // is little endian, not whether the host is?
3197 *(UInt*)(m + 0) = ls4B;
3198 *(UInt*)(m + 4) = ms4B;
3199 } else {
3200 *(UInt*)(m + 0) = ms4B;
3201 *(UInt*)(m + 4) = ls4B;
3202 }
3203 nonptr_or_unknown_range(m, 8);
3204}
3205
3206// This handles 64 bit non pointer stores on 64 bit targets.
3207// It must not be called on 32 bit targets.
3208static VG_REGPARM(3)
3209void check_store8_all8B(Addr m, Seg* mptr_vseg, UWord all8B)
3210{
3211 tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */
3212# if SC_SEGS
3213 checkSeg(mptr_vseg);
3214# endif
3215 check_load_or_store(/*is_write*/True, m, 8, mptr_vseg);
3216 // Actually *do* the STORE here
3217 *(ULong*)m = all8B;
3218 nonptr_or_unknown_range(m, 8);
3219}
3220
3221// This handles 64 bit stores on 64 bit targets. It must
3222// not be called on 32 bit targets.
3223static VG_REGPARM(3)
3224void check_store8_P(Addr m, Seg* mptr_vseg, UWord t, Seg* t_vseg)
3225{
3226 tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */
3227# if SC_SEGS
3228 checkSeg(t_vseg);
3229 checkSeg(mptr_vseg);
3230# endif
3231 check_load_or_store(/*is_write*/True, m, 8, mptr_vseg);
3232 // Actually *do* the STORE here
3233 *(ULong*)m = t;
sewardj2d630e22009-07-09 10:52:03 +00003234 do_shadow_store8_P( m, t_vseg );
sewardj024598e2008-09-18 14:43:05 +00003235}
3236
sewardj1c0ce7a2009-07-01 08:10:49 +00003237// This handles 64 bit store-conditionals on 64 bit targets. It must
3238// not be called on 32 bit targets.
3239static VG_REGPARM(3)
3240UWord check_store8C_P(Addr m, Seg* mptr_vseg, UWord t, Seg* t_vseg)
3241{
3242 UWord success;
3243 tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */
3244# if SC_SEGS
3245 checkSeg(t_vseg);
3246 checkSeg(mptr_vseg);
3247# endif
3248 check_load_or_store(/*is_write*/True, m, 8, mptr_vseg);
3249 // Actually *do* the STORE here
3250 success = do_store_conditional_64( m, t );
sewardj2d630e22009-07-09 10:52:03 +00003251 if (success)
3252 do_shadow_store8_P( m, t_vseg );
sewardj1c0ce7a2009-07-01 08:10:49 +00003253 return success;
3254}
3255
sewardj024598e2008-09-18 14:43:05 +00003256// This handles 32 bit stores on 32 bit targets. It must
3257// not be called on 64 bit targets.
3258static VG_REGPARM(3)
3259void check_store4_P(Addr m, Seg* mptr_vseg, UWord t, Seg* t_vseg)
3260{
3261 tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */
3262# if SC_SEGS
3263 checkSeg(t_vseg);
3264 checkSeg(mptr_vseg);
3265# endif
3266 check_load_or_store(/*is_write*/True, m, 4, mptr_vseg);
3267 // Actually *do* the STORE here
3268 *(UInt*)m = t;
sewardj2d630e22009-07-09 10:52:03 +00003269 do_shadow_store4_P( m, t_vseg );
sewardj024598e2008-09-18 14:43:05 +00003270}
3271
sewardj1c0ce7a2009-07-01 08:10:49 +00003272// This handles 32 bit store-conditionals on 32 bit targets. It must
3273// not be called on 64 bit targets.
3274static VG_REGPARM(3)
3275UWord check_store4C_P(Addr m, Seg* mptr_vseg, UWord t, Seg* t_vseg)
3276{
3277 UWord success;
3278 tl_assert(sizeof(UWord) == 4); /* DO NOT REMOVE */
3279# if SC_SEGS
3280 checkSeg(t_vseg);
3281 checkSeg(mptr_vseg);
3282# endif
3283 check_load_or_store(/*is_write*/True, m, 4, mptr_vseg);
3284 // Actually *do* the STORE here
3285 success = do_store_conditional_32( m, t );
sewardj2d630e22009-07-09 10:52:03 +00003286 if (success)
3287 do_shadow_store4_P( m, t_vseg );
sewardj1c0ce7a2009-07-01 08:10:49 +00003288 return success;
3289}
3290
sewardj024598e2008-09-18 14:43:05 +00003291// Used for both 32 bit and 64 bit targets.
3292static VG_REGPARM(3)
3293void check_store4(Addr m, Seg* mptr_vseg, UWord t)
3294{
3295# if SC_SEGS
3296 checkSeg(mptr_vseg);
3297# endif
3298 check_load_or_store(/*is_write*/True, m, 4, mptr_vseg);
3299 // Actually *do* the STORE here (Nb: cast must be to 4-byte type!)
3300 *(UInt*)m = t;
3301 nonptr_or_unknown_range(m, 4);
3302}
3303
sewardj1c0ce7a2009-07-01 08:10:49 +00003304// Used for 32-bit store-conditionals on 64 bit targets only. It must
3305// not be called on 32 bit targets.
3306static VG_REGPARM(3)
3307UWord check_store4C(Addr m, Seg* mptr_vseg, UWord t)
3308{
3309 UWord success;
3310 tl_assert(sizeof(UWord) == 8); /* DO NOT REMOVE */
3311# if SC_SEGS
3312 checkSeg(mptr_vseg);
3313# endif
3314 check_load_or_store(/*is_write*/True, m, 4, mptr_vseg);
3315 // Actually *do* the STORE here
3316 success = do_store_conditional_32( m, t );
sewardj2d630e22009-07-09 10:52:03 +00003317 if (success)
3318 nonptr_or_unknown_range(m, 4);
sewardj1c0ce7a2009-07-01 08:10:49 +00003319 return success;
3320}
3321
sewardj024598e2008-09-18 14:43:05 +00003322// Used for both 32 bit and 64 bit targets.
3323static VG_REGPARM(3)
3324void check_store2(Addr m, Seg* mptr_vseg, UWord t)
3325{
3326# if SC_SEGS
3327 checkSeg(mptr_vseg);
3328# endif
3329 check_load_or_store(/*is_write*/True, m, 2, mptr_vseg);
3330 // Actually *do* the STORE here (Nb: cast must be to 2-byte type!)
3331 *(UShort*)m = t;
3332 nonptr_or_unknown_range(m, 2);
3333}
3334
3335// Used for both 32 bit and 64 bit targets.
3336static VG_REGPARM(3)
3337void check_store1(Addr m, Seg* mptr_vseg, UWord t)
3338{
3339# if SC_SEGS
3340 checkSeg(mptr_vseg);
3341# endif
3342 check_load_or_store(/*is_write*/True, m, 1, mptr_vseg);
3343 // Actually *do* the STORE here (Nb: cast must be to 1-byte type!)
3344 *(UChar*)m = t;
3345 nonptr_or_unknown_range(m, 1);
3346}
3347
3348
3349// Nb: if the result is BOTTOM, return immedately -- don't let BOTTOM
3350// be changed to NONPTR by a range check on the result.
3351#define BINOP(bt, nn, nu, np, un, uu, up, pn, pu, pp) \
3352 if (BOTTOM == seg1 || BOTTOM == seg2) { bt; \
3353 } else if (NONPTR == seg1) { if (NONPTR == seg2) { nn; } \
3354 else if (UNKNOWN == seg2) { nu; } \
3355 else { np; } \
3356 } else if (UNKNOWN == seg1) { if (NONPTR == seg2) { un; } \
3357 else if (UNKNOWN == seg2) { uu; } \
3358 else { up; } \
3359 } else { if (NONPTR == seg2) { pn; } \
3360 else if (UNKNOWN == seg2) { pu; } \
3361 else { pp; } \
3362 }
3363
3364#define BINERROR(opname) \
3365 h_record_arith_error(seg1, seg2, opname); \
3366 out = NONPTR
3367
3368
3369// -------------
3370// + | n ? p
3371// -------------
3372// n | n ? p
3373// ? | ? ? ?
3374// p | p ? e (all results become n if they look like a non-pointer)
3375// -------------
3376static Seg* do_addW_result(Seg* seg1, Seg* seg2, UWord result, HChar* opname)
3377{
3378 Seg* out;
3379# if SC_SEGS
3380 checkSeg(seg1);
3381 checkSeg(seg2);
3382# endif
3383 BINOP(
3384 return BOTTOM,
3385 out = NONPTR, out = UNKNOWN, out = seg2,
3386 out = UNKNOWN, out = UNKNOWN, out = UNKNOWN,
3387 out = seg1, out = UNKNOWN, BINERROR(opname)
3388 );
3389 return ( looks_like_a_pointer(result) ? out : NONPTR );
3390}
3391
3392static VG_REGPARM(3) Seg* do_addW(Seg* seg1, Seg* seg2, UWord result)
3393{
3394 Seg* out;
3395# if SC_SEGS
3396 checkSeg(seg1);
3397 checkSeg(seg2);
3398# endif
3399 out = do_addW_result(seg1, seg2, result, "Add32/Add64");
3400# if SC_SEGS
3401 checkSeg(out);
3402# endif
3403 return out;
3404}
3405
3406// -------------
3407// - | n ? p (Nb: operation is seg1 - seg2)
3408// -------------
3409// n | n ? n+ (+) happens a lot due to "cmp", but result should never
3410// ? | ? ? n/B be used, so give 'n'
3411// p | p p? n*/B (*) and possibly link the segments
3412// -------------
3413static VG_REGPARM(3) Seg* do_subW(Seg* seg1, Seg* seg2, UWord result)
3414{
3415 Seg* out;
3416# if SC_SEGS
3417 checkSeg(seg1);
3418 checkSeg(seg2);
3419# endif
3420 // Nb: when returning BOTTOM, don't let it go through the range-check;
3421 // a segment linking offset can easily look like a nonptr.
3422 BINOP(
3423 return BOTTOM,
3424 out = NONPTR, out = UNKNOWN, out = NONPTR,
3425 out = UNKNOWN, out = UNKNOWN, return BOTTOM,
3426 out = seg1, out = seg1/*??*/, return BOTTOM
3427 );
3428 #if 0
3429 // This is for the p-p segment-linking case
3430 Seg end2 = seg2;
3431 while (end2->links != seg2) end2 = end2->links;
3432 end2->links = seg1->links;
3433 seg1->links = seg2;
3434 return NONPTR;
3435 #endif
3436 return ( looks_like_a_pointer(result) ? out : NONPTR );
3437}
3438
3439// -------------
3440// & | n ? p
3441// -------------
3442// n | n ? p
3443// ? | ? ? ?
3444// p | p ? * (*) if p1==p2 then p else e (see comment)
3445// -------------
3446/* Seems to be OK to And two pointers:
3447 testq %ptr1,%ptr2
3448 jnz ..
3449 which possibly derives from
3450 if (ptr1 & ptr2) { A } else { B }
3451 not sure what that means
3452*/
3453static VG_REGPARM(3) Seg* do_andW(Seg* seg1, Seg* seg2,
3454 UWord result, UWord args_diff)
3455{
3456 Seg* out;
3457 if (0 == args_diff) {
3458 // p1==p2
3459 out = seg1;
3460 } else {
3461 BINOP(
3462 return BOTTOM,
3463 out = NONPTR, out = UNKNOWN, out = seg2,
3464 out = UNKNOWN, out = UNKNOWN, out = UNKNOWN,
3465 out = seg1, out = UNKNOWN, out = NONPTR
3466 /*BINERROR("And32/And64")*/
3467 );
3468 }
3469 out = ( looks_like_a_pointer(result) ? out : NONPTR );
3470 return out;
3471}
3472
3473// -------------
3474// `|`| n ? p
3475// -------------
3476// n | n ? p
3477// ? | ? ? ?
3478// p | p ? n
3479// -------------
3480/* It's OK to Or two pointers together, but the result definitely
3481 isn't a pointer. Why would you want to do that? Because of this:
3482 char* p1 = malloc(..);
3483 char* p2 = malloc(..);
3484 ...
3485 if (p1 || p2) { .. }
3486 In this case gcc on x86/amd64 quite literally or-s the two pointers
3487 together and throws away the result, the purpose of which is merely
3488 to sets %eflags.Z/%rflags.Z. So we have to allow it.
3489*/
3490static VG_REGPARM(3) Seg* do_orW(Seg* seg1, Seg* seg2, UWord result)
3491{
3492 Seg* out;
3493 BINOP(
3494 return BOTTOM,
3495 out = NONPTR, out = UNKNOWN, out = seg2,
3496 out = UNKNOWN, out = UNKNOWN, out = UNKNOWN,
3497 out = seg1, out = UNKNOWN, out = NONPTR
3498 );
3499 out = ( looks_like_a_pointer(result) ? out : NONPTR );
3500 return out;
3501}
3502
3503// -------------
3504// ~ | n ? p
3505// -------------
3506// | n n n
3507// -------------
3508static VG_REGPARM(2) Seg* do_notW(Seg* seg1, UWord result)
3509{
3510# if SC_SEGS
3511 checkSeg(seg1);
3512# endif
3513 if (BOTTOM == seg1) return BOTTOM;
3514 return NONPTR;
3515}
3516
3517// Pointers are rarely multiplied, but sometimes legitimately, eg. as hash
3518// function inputs. But two pointers args --> error.
3519// Pretend it always returns a nonptr. Maybe improve later.
3520static VG_REGPARM(2) Seg* do_mulW(Seg* seg1, Seg* seg2)
3521{
3522# if SC_SEGS
3523 checkSeg(seg1);
3524 checkSeg(seg2);
3525# endif
3526 if (is_known_segment(seg1) && is_known_segment(seg2))
3527 h_record_arith_error(seg1, seg2, "Mul32/Mul64");
3528 return NONPTR;
3529}
3530
3531
3532/*--------------------------------------------------------------------*/
3533/*--- Instrumentation ---*/
3534/*--------------------------------------------------------------------*/
3535
3536/* The h_ instrumenter that follows is complex, since it deals with
3537 shadow value computation.
3538
3539 It also needs to generate instrumentation for the sg_ side of
3540 things. That's relatively straightforward. However, rather than
3541 confuse the code herein any further, we simply delegate the problem
3542 to sg_main.c, by using the four functions
3543 sg_instrument_{init,fini,IRStmt,final_jump}. These four completely
3544 abstractify the sg_ instrumentation. See comments in sg_main.c's
3545 instrumentation section for further details. */
3546
sewardje6451332009-07-09 10:45:11 +00003547
3548/* Carries info about a particular tmp. The tmp's number is not
3549 recorded, as this is implied by (equal to) its index in the tmpMap
3550 in PCEnv. The tmp's type is also not recorded, as this is present
3551 in PCEnv.sb->tyenv.
3552
3553 When .kind is NonShad, .shadow may give the identity of the temp
3554 currently holding the associated shadow value, or it may be
3555 IRTemp_INVALID if code to compute the shadow has not yet been
3556 emitted.
3557
3558 When .kind is Shad tmp holds a shadow value, and so .shadow must be
3559 IRTemp_INVALID, since it is illogical for a shadow tmp itself to be
3560 shadowed.
3561*/
3562typedef
3563 enum { NonShad=1, Shad=2 }
3564 TempKind;
3565
3566typedef
3567 struct {
3568 TempKind kind;
3569 IRTemp shadow;
3570 }
3571 TempMapEnt;
3572
3573
3574
sewardj024598e2008-09-18 14:43:05 +00003575/* Carries around state during Ptrcheck instrumentation. */
3576typedef
3577 struct {
3578 /* MODIFIED: the superblock being constructed. IRStmts are
3579 added. */
sewardje6451332009-07-09 10:45:11 +00003580 IRSB* sb;
sewardj024598e2008-09-18 14:43:05 +00003581 Bool trace;
3582
sewardje6451332009-07-09 10:45:11 +00003583 /* MODIFIED: a table [0 .. #temps_in_sb-1] which gives the
3584 current kind and possibly shadow temps for each temp in the
3585 IRSB being constructed. Note that it does not contain the
3586 type of each tmp. If you want to know the type, look at the
3587 relevant entry in sb->tyenv. It follows that at all times
3588 during the instrumentation process, the valid indices for
3589 tmpMap and sb->tyenv are identical, being 0 .. N-1 where N is
3590 total number of NonShad and Shad temps allocated so far.
3591
3592 The reason for this strange split (types in one place, all
3593 other info in another) is that we need the types to be
3594 attached to sb so as to make it possible to do
3595 "typeOfIRExpr(mce->bb->tyenv, ...)" at various places in the
3596 instrumentation process.
3597
3598 Note that only integer temps of the guest word size are
3599 shadowed, since it is impossible (or meaningless) to hold a
3600 pointer in any other type of temp. */
3601 XArray* /* of TempMapEnt */ qmpMap;
sewardj024598e2008-09-18 14:43:05 +00003602
3603 /* READONLY: the host word type. Needed for constructing
3604 arguments of type 'HWord' to be passed to helper functions.
3605 Ity_I32 or Ity_I64 only. */
3606 IRType hWordTy;
3607
3608 /* READONLY: the guest word type, Ity_I32 or Ity_I64 only. */
3609 IRType gWordTy;
3610
3611 /* READONLY: the guest state size, so we can generate shadow
3612 offsets correctly. */
3613 Int guest_state_sizeB;
3614 }
3615 PCEnv;
3616
3617/* SHADOW TMP MANAGEMENT. Shadow tmps are allocated lazily (on
3618 demand), as they are encountered. This is for two reasons.
3619
3620 (1) (less important reason): Many original tmps are unused due to
3621 initial IR optimisation, and we do not want to spaces in tables
3622 tracking them.
3623
3624 Shadow IRTemps are therefore allocated on demand. pce.tmpMap is a
3625 table indexed [0 .. n_types-1], which gives the current shadow for
3626 each original tmp, or INVALID_IRTEMP if none is so far assigned.
3627 It is necessary to support making multiple assignments to a shadow
3628 -- specifically, after testing a shadow for definedness, it needs
3629 to be made defined. But IR's SSA property disallows this.
3630
3631 (2) (more important reason): Therefore, when a shadow needs to get
3632 a new value, a new temporary is created, the value is assigned to
3633 that, and the tmpMap is updated to reflect the new binding.
3634
3635 A corollary is that if the tmpMap maps a given tmp to
3636 IRTemp_INVALID and we are hoping to read that shadow tmp, it means
3637 there's a read-before-write error in the original tmps. The IR
3638 sanity checker should catch all such anomalies, however.
3639*/
3640
sewardje6451332009-07-09 10:45:11 +00003641/* Create a new IRTemp of type 'ty' and kind 'kind', and add it to
3642 both the table in pce->sb and to our auxiliary mapping. Note that
3643 newTemp may cause pce->tmpMap to resize, hence previous results
3644 from VG_(indexXA)(pce->tmpMap) are invalidated. */
3645static IRTemp newTemp ( PCEnv* pce, IRType ty, TempKind kind )
3646{
3647 Word newIx;
3648 TempMapEnt ent;
3649 IRTemp tmp = newIRTemp(pce->sb->tyenv, ty);
3650 ent.kind = kind;
3651 ent.shadow = IRTemp_INVALID;
3652 newIx = VG_(addToXA)( pce->qmpMap, &ent );
3653 tl_assert(newIx == (Word)tmp);
3654 return tmp;
3655}
3656
sewardj024598e2008-09-18 14:43:05 +00003657/* Find the tmp currently shadowing the given original tmp. If none
3658 so far exists, allocate one. */
3659static IRTemp findShadowTmp ( PCEnv* pce, IRTemp orig )
3660{
sewardje6451332009-07-09 10:45:11 +00003661 TempMapEnt* ent;
3662 /* VG_(indexXA) range-checks 'orig', hence no need to check
3663 here. */
3664 ent = (TempMapEnt*)VG_(indexXA)( pce->qmpMap, (Word)orig );
3665 tl_assert(ent->kind == NonShad);
3666 if (ent->shadow == IRTemp_INVALID) {
3667 IRTemp shadow = newTemp( pce, pce->gWordTy, Shad );
3668 /* newTemp may cause pce->tmpMap to resize, hence previous results
3669 from VG_(indexXA) are invalid. */
3670 ent = (TempMapEnt*)VG_(indexXA)( pce->qmpMap, (Word)orig );
3671 tl_assert(ent->kind == NonShad);
3672 tl_assert(ent->shadow == IRTemp_INVALID);
3673 ent->shadow = shadow;
sewardj024598e2008-09-18 14:43:05 +00003674 }
sewardje6451332009-07-09 10:45:11 +00003675 return ent->shadow;
sewardj024598e2008-09-18 14:43:05 +00003676}
3677
3678/* Allocate a new shadow for the given original tmp. This means any
3679 previous shadow is abandoned. This is needed because it is
3680 necessary to give a new value to a shadow once it has been tested
3681 for undefinedness, but unfortunately IR's SSA property disallows
3682 this. Instead we must abandon the old shadow, allocate a new one
sewardje6451332009-07-09 10:45:11 +00003683 and use that instead.
3684
3685 This is the same as findShadowTmp, except we don't bother to see
3686 if a shadow temp already existed -- we simply allocate a new one
3687 regardless. */
sewardj024598e2008-09-18 14:43:05 +00003688static IRTemp newShadowTmp ( PCEnv* pce, IRTemp orig )
3689{
sewardje6451332009-07-09 10:45:11 +00003690 TempMapEnt* ent;
3691 /* VG_(indexXA) range-checks 'orig', hence no need to check
3692 here. */
3693 ent = (TempMapEnt*)VG_(indexXA)( pce->qmpMap, (Word)orig );
3694 tl_assert(ent->kind == NonShad);
3695 if (1) {
3696 IRTemp shadow = newTemp( pce, pce->gWordTy, Shad );
3697 /* newTemp may cause pce->tmpMap to resize, hence previous results
3698 from VG_(indexXA) are invalid. */
3699 ent = (TempMapEnt*)VG_(indexXA)( pce->qmpMap, (Word)orig );
3700 tl_assert(ent->kind == NonShad);
3701 ent->shadow = shadow;
3702 return shadow;
3703 }
3704 /* NOTREACHED */
3705 tl_assert(0);
sewardj024598e2008-09-18 14:43:05 +00003706}
3707
3708
3709/*------------------------------------------------------------*/
3710/*--- IRAtoms -- a subset of IRExprs ---*/
3711/*------------------------------------------------------------*/
3712
3713/* An atom is either an IRExpr_Const or an IRExpr_Tmp, as defined by
3714 isIRAtom() in libvex_ir.h. Because this instrumenter expects flat
3715 input, most of this code deals in atoms. Usefully, a value atom
3716 always has a V-value which is also an atom: constants are shadowed
3717 by constants, and temps are shadowed by the corresponding shadow
3718 temporary. */
3719
3720typedef IRExpr IRAtom;
3721
3722//zz /* (used for sanity checks only): is this an atom which looks
3723//zz like it's from original code? */
3724//zz static Bool isOriginalAtom ( PCEnv* pce, IRAtom* a1 )
3725//zz {
3726//zz if (a1->tag == Iex_Const)
3727//zz return True;
3728//zz if (a1->tag == Iex_RdTmp && a1->Iex.RdTmp.tmp < pce->n_originalTmps)
3729//zz return True;
3730//zz return False;
3731//zz }
3732//zz
3733//zz /* (used for sanity checks only): is this an atom which looks
3734//zz like it's from shadow code? */
3735//zz static Bool isShadowAtom ( PCEnv* pce, IRAtom* a1 )
3736//zz {
3737//zz if (a1->tag == Iex_Const)
3738//zz return True;
3739//zz if (a1->tag == Iex_RdTmp && a1->Iex.RdTmp.tmp >= pce->n_originalTmps)
3740//zz return True;
3741//zz return False;
3742//zz }
3743//zz
3744//zz /* (used for sanity checks only): check that both args are atoms and
3745//zz are identically-kinded. */
3746//zz static Bool sameKindedAtoms ( IRAtom* a1, IRAtom* a2 )
3747//zz {
3748//zz if (a1->tag == Iex_RdTmp && a2->tag == Iex_RdTmp)
3749//zz return True;
3750//zz if (a1->tag == Iex_Const && a2->tag == Iex_Const)
3751//zz return True;
3752//zz return False;
3753//zz }
3754
3755
3756/*------------------------------------------------------------*/
3757/*--- Constructing IR fragments ---*/
3758/*------------------------------------------------------------*/
3759
3760/* add stmt to a bb */
3761static inline void stmt ( HChar cat, PCEnv* pce, IRStmt* st ) {
3762 if (pce->trace) {
3763 VG_(printf)(" %c: ", cat);
3764 ppIRStmt(st);
3765 VG_(printf)("\n");
3766 }
sewardje6451332009-07-09 10:45:11 +00003767 addStmtToIRSB(pce->sb, st);
sewardj024598e2008-09-18 14:43:05 +00003768}
3769
3770/* assign value to tmp */
3771static inline
3772void assign ( HChar cat, PCEnv* pce, IRTemp tmp, IRExpr* expr ) {
3773 stmt(cat, pce, IRStmt_WrTmp(tmp,expr));
3774}
3775
3776/* build various kinds of expressions */
3777#define binop(_op, _arg1, _arg2) IRExpr_Binop((_op),(_arg1),(_arg2))
3778#define unop(_op, _arg) IRExpr_Unop((_op),(_arg))
3779#define mkU8(_n) IRExpr_Const(IRConst_U8(_n))
3780#define mkU16(_n) IRExpr_Const(IRConst_U16(_n))
3781#define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
3782#define mkU64(_n) IRExpr_Const(IRConst_U64(_n))
3783#define mkV128(_n) IRExpr_Const(IRConst_V128(_n))
3784#define mkexpr(_tmp) IRExpr_RdTmp((_tmp))
3785
3786/* Bind the given expression to a new temporary, and return the
3787 temporary. This effectively converts an arbitrary expression into
3788 an atom.
3789
3790 'ty' is the type of 'e' and hence the type that the new temporary
3791 needs to be. But passing it is redundant, since we can deduce the
3792 type merely by inspecting 'e'. So at least that fact to assert
3793 that the two types agree. */
3794static IRAtom* assignNew ( HChar cat, PCEnv* pce, IRType ty, IRExpr* e ) {
3795 IRTemp t;
sewardje6451332009-07-09 10:45:11 +00003796 IRType tyE = typeOfIRExpr(pce->sb->tyenv, e);
sewardj024598e2008-09-18 14:43:05 +00003797 tl_assert(tyE == ty); /* so 'ty' is redundant (!) */
sewardje6451332009-07-09 10:45:11 +00003798 t = newTemp(pce, ty, Shad);
sewardj024598e2008-09-18 14:43:05 +00003799 assign(cat, pce, t, e);
3800 return mkexpr(t);
3801}
3802
3803
3804
3805//-----------------------------------------------------------------------
3806// Approach taken for range-checking for NONPTR/UNKNOWN-ness as follows.
3807//
3808// Range check (NONPTR/seg):
3809// - after modifying a word-sized value in/into a TempReg:
3810// - {ADD, SUB, ADC, SBB, AND, OR, XOR, LEA, LEA2, NEG, NOT}L
3811// - BSWAP
3812//
3813// Range check (NONPTR/UNKNOWN):
3814// - when introducing a new word-sized value into a TempReg:
3815// - MOVL l, t2
3816//
3817// - when copying a word-sized value which lacks a corresponding segment
3818// into a TempReg:
3819// - straddled LDL
3820//
3821// - when a sub-word of a word (or two) is updated:
3822// - SHROTL
3823// - {ADD, SUB, ADC, SBB, AND, OR, XOR, SHROT, NEG, NOT}[WB]
3824// - PUT[WB]
3825// - straddled STL (2 range checks)
3826// - straddled STW (2 range checks)
3827// - unstraddled STW
3828// - STB
3829//
3830// Just copy:
3831// - when copying word-sized values:
3832// - MOVL t1, t2 (--optimise=no only)
3833// - CMOV
3834// - GETL, PUTL
3835// - unstraddled LDL, unstraddled STL
3836//
3837// - when barely changing
3838// - INC[LWB]/DEC[LWB]
3839//
3840// Set to NONPTR:
3841// - after copying a sub-word value into a TempReg:
3842// - MOV[WB] l, t2
3843// - GET[WB]
3844// - unstraddled LDW
3845// - straddled LDW
3846// - LDB
3847// - POP[WB]
3848//
3849// - after copying an obvious non-ptr into a TempReg:
3850// - GETF
3851// - CC2VAL
3852// - POPL
3853//
3854// - after copying an obvious non-ptr into a memory word:
3855// - FPU_W
3856//
3857// Do nothing:
3858// - LOCK, INCEIP
3859// - WIDEN[WB]
3860// - JMP, JIFZ
3861// - CALLM_[SE], PUSHL, CALLM, CLEAR
3862// - FPU, FPU_R (and similar MMX/SSE ones)
3863//
3864
3865
3866
3867
3868/* Call h_fn (name h_nm) with the given arg, and return a new IRTemp
3869 holding the result. The arg must be a word-typed atom. Callee
3870 must be a VG_REGPARM(1) function. */
3871__attribute__((noinline))
3872static IRTemp gen_dirty_W_W ( PCEnv* pce, void* h_fn, HChar* h_nm,
3873 IRExpr* a1 )
3874{
3875 IRTemp res;
3876 IRDirty* di;
3877 tl_assert(isIRAtom(a1));
sewardje6451332009-07-09 10:45:11 +00003878 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
3879 res = newTemp(pce, pce->gWordTy, Shad);
sewardj024598e2008-09-18 14:43:05 +00003880 di = unsafeIRDirty_1_N( res, 1/*regparms*/,
3881 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
3882 mkIRExprVec_1( a1 ) );
3883 stmt( 'I', pce, IRStmt_Dirty(di) );
3884 return res;
3885}
3886
3887/* Two-arg version of gen_dirty_W_W. Callee must be a VG_REGPARM(2)
3888 function.*/
3889static IRTemp gen_dirty_W_WW ( PCEnv* pce, void* h_fn, HChar* h_nm,
3890 IRExpr* a1, IRExpr* a2 )
3891{
3892 IRTemp res;
3893 IRDirty* di;
3894 tl_assert(isIRAtom(a1));
3895 tl_assert(isIRAtom(a2));
sewardje6451332009-07-09 10:45:11 +00003896 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
3897 tl_assert(typeOfIRExpr(pce->sb->tyenv, a2) == pce->gWordTy);
3898 res = newTemp(pce, pce->gWordTy, Shad);
sewardj024598e2008-09-18 14:43:05 +00003899 di = unsafeIRDirty_1_N( res, 2/*regparms*/,
3900 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
3901 mkIRExprVec_2( a1, a2 ) );
3902 stmt( 'I', pce, IRStmt_Dirty(di) );
3903 return res;
3904}
3905
3906/* Three-arg version of gen_dirty_W_W. Callee must be a VG_REGPARM(3)
3907 function.*/
3908static IRTemp gen_dirty_W_WWW ( PCEnv* pce, void* h_fn, HChar* h_nm,
3909 IRExpr* a1, IRExpr* a2, IRExpr* a3 )
3910{
3911 IRTemp res;
3912 IRDirty* di;
3913 tl_assert(isIRAtom(a1));
3914 tl_assert(isIRAtom(a2));
3915 tl_assert(isIRAtom(a3));
sewardje6451332009-07-09 10:45:11 +00003916 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
3917 tl_assert(typeOfIRExpr(pce->sb->tyenv, a2) == pce->gWordTy);
3918 tl_assert(typeOfIRExpr(pce->sb->tyenv, a3) == pce->gWordTy);
3919 res = newTemp(pce, pce->gWordTy, Shad);
sewardj024598e2008-09-18 14:43:05 +00003920 di = unsafeIRDirty_1_N( res, 3/*regparms*/,
3921 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
3922 mkIRExprVec_3( a1, a2, a3 ) );
3923 stmt( 'I', pce, IRStmt_Dirty(di) );
3924 return res;
3925}
3926
3927/* Four-arg version of gen_dirty_W_W. Callee must be a VG_REGPARM(3)
3928 function.*/
3929static IRTemp gen_dirty_W_WWWW ( PCEnv* pce, void* h_fn, HChar* h_nm,
3930 IRExpr* a1, IRExpr* a2,
3931 IRExpr* a3, IRExpr* a4 )
3932{
3933 IRTemp res;
3934 IRDirty* di;
3935 tl_assert(isIRAtom(a1));
3936 tl_assert(isIRAtom(a2));
3937 tl_assert(isIRAtom(a3));
3938 tl_assert(isIRAtom(a4));
sewardje6451332009-07-09 10:45:11 +00003939 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
3940 tl_assert(typeOfIRExpr(pce->sb->tyenv, a2) == pce->gWordTy);
3941 tl_assert(typeOfIRExpr(pce->sb->tyenv, a3) == pce->gWordTy);
3942 tl_assert(typeOfIRExpr(pce->sb->tyenv, a4) == pce->gWordTy);
3943 res = newTemp(pce, pce->gWordTy, Shad);
sewardj024598e2008-09-18 14:43:05 +00003944 di = unsafeIRDirty_1_N( res, 3/*regparms*/,
3945 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
3946 mkIRExprVec_4( a1, a2, a3, a4 ) );
3947 stmt( 'I', pce, IRStmt_Dirty(di) );
3948 return res;
3949}
3950
3951/* Version of gen_dirty_W_WW with no return value. Callee must be a
sewardj2d630e22009-07-09 10:52:03 +00003952 VG_REGPARM(2) function. If guard is non-NULL then it is used to
3953 conditionalise the call. */
3954static void gen_dirty_v_WW ( PCEnv* pce, IRExpr* guard,
3955 void* h_fn, HChar* h_nm,
sewardj024598e2008-09-18 14:43:05 +00003956 IRExpr* a1, IRExpr* a2 )
3957{
3958 IRDirty* di;
3959 tl_assert(isIRAtom(a1));
3960 tl_assert(isIRAtom(a2));
sewardje6451332009-07-09 10:45:11 +00003961 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
3962 tl_assert(typeOfIRExpr(pce->sb->tyenv, a2) == pce->gWordTy);
sewardj024598e2008-09-18 14:43:05 +00003963 di = unsafeIRDirty_0_N( 2/*regparms*/,
3964 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
3965 mkIRExprVec_2( a1, a2 ) );
sewardj2d630e22009-07-09 10:52:03 +00003966 if (guard)
3967 di->guard = guard;
sewardj024598e2008-09-18 14:43:05 +00003968 stmt( 'I', pce, IRStmt_Dirty(di) );
3969}
3970
3971/* Version of gen_dirty_W_WWW with no return value. Callee must be a
3972 VG_REGPARM(3) function.*/
3973static void gen_dirty_v_WWW ( PCEnv* pce, void* h_fn, HChar* h_nm,
3974 IRExpr* a1, IRExpr* a2, IRExpr* a3 )
3975{
3976 IRDirty* di;
3977 tl_assert(isIRAtom(a1));
3978 tl_assert(isIRAtom(a2));
3979 tl_assert(isIRAtom(a3));
sewardje6451332009-07-09 10:45:11 +00003980 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
3981 tl_assert(typeOfIRExpr(pce->sb->tyenv, a2) == pce->gWordTy);
3982 tl_assert(typeOfIRExpr(pce->sb->tyenv, a3) == pce->gWordTy);
sewardj024598e2008-09-18 14:43:05 +00003983 di = unsafeIRDirty_0_N( 3/*regparms*/,
3984 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
3985 mkIRExprVec_3( a1, a2, a3 ) );
3986 stmt( 'I', pce, IRStmt_Dirty(di) );
3987}
3988
3989/* Version of gen_dirty_v_WWW for 4 arguments. Callee must be a
3990 VG_REGPARM(3) function.*/
3991static void gen_dirty_v_WWWW ( PCEnv* pce, void* h_fn, HChar* h_nm,
3992 IRExpr* a1, IRExpr* a2,
3993 IRExpr* a3, IRExpr* a4 )
3994{
3995 IRDirty* di;
3996 tl_assert(isIRAtom(a1));
3997 tl_assert(isIRAtom(a2));
3998 tl_assert(isIRAtom(a3));
3999 tl_assert(isIRAtom(a4));
sewardje6451332009-07-09 10:45:11 +00004000 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
4001 tl_assert(typeOfIRExpr(pce->sb->tyenv, a2) == pce->gWordTy);
4002 tl_assert(typeOfIRExpr(pce->sb->tyenv, a3) == pce->gWordTy);
4003 tl_assert(typeOfIRExpr(pce->sb->tyenv, a4) == pce->gWordTy);
sewardj024598e2008-09-18 14:43:05 +00004004 di = unsafeIRDirty_0_N( 3/*regparms*/,
4005 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
4006 mkIRExprVec_4( a1, a2, a3, a4 ) );
4007 stmt( 'I', pce, IRStmt_Dirty(di) );
4008}
4009
4010/* Version of gen_dirty_v_WWW for 6 arguments. Callee must be a
4011 VG_REGPARM(3) function.*/
4012static void gen_dirty_v_6W ( PCEnv* pce, void* h_fn, HChar* h_nm,
4013 IRExpr* a1, IRExpr* a2, IRExpr* a3,
4014 IRExpr* a4, IRExpr* a5, IRExpr* a6 )
4015{
4016 IRDirty* di;
4017 tl_assert(isIRAtom(a1));
4018 tl_assert(isIRAtom(a2));
4019 tl_assert(isIRAtom(a3));
4020 tl_assert(isIRAtom(a4));
4021 tl_assert(isIRAtom(a5));
4022 tl_assert(isIRAtom(a6));
sewardje6451332009-07-09 10:45:11 +00004023 tl_assert(typeOfIRExpr(pce->sb->tyenv, a1) == pce->gWordTy);
4024 tl_assert(typeOfIRExpr(pce->sb->tyenv, a2) == pce->gWordTy);
4025 tl_assert(typeOfIRExpr(pce->sb->tyenv, a3) == pce->gWordTy);
4026 tl_assert(typeOfIRExpr(pce->sb->tyenv, a4) == pce->gWordTy);
4027 tl_assert(typeOfIRExpr(pce->sb->tyenv, a5) == pce->gWordTy);
4028 tl_assert(typeOfIRExpr(pce->sb->tyenv, a6) == pce->gWordTy);
sewardj024598e2008-09-18 14:43:05 +00004029 di = unsafeIRDirty_0_N( 3/*regparms*/,
4030 h_nm, VG_(fnptr_to_fnentry)( h_fn ),
4031 mkIRExprVec_6( a1, a2, a3, a4, a5, a6 ) );
4032 stmt( 'I', pce, IRStmt_Dirty(di) );
4033}
4034
4035static IRAtom* uwiden_to_host_word ( PCEnv* pce, IRAtom* a )
4036{
sewardje6451332009-07-09 10:45:11 +00004037 IRType a_ty = typeOfIRExpr(pce->sb->tyenv, a);
sewardj024598e2008-09-18 14:43:05 +00004038 tl_assert(isIRAtom(a));
4039 if (pce->hWordTy == Ity_I32) {
4040 switch (a_ty) {
4041 case Ity_I8:
4042 return assignNew( 'I', pce, Ity_I32, unop(Iop_8Uto32, a) );
4043 case Ity_I16:
4044 return assignNew( 'I', pce, Ity_I32, unop(Iop_16Uto32, a) );
4045 default:
4046 ppIRType(a_ty);
4047 tl_assert(0);
4048 }
4049 } else {
4050 tl_assert(pce->hWordTy == Ity_I64);
4051 switch (a_ty) {
4052 case Ity_I8:
4053 return assignNew( 'I', pce, Ity_I64, unop(Iop_8Uto64, a) );
4054 case Ity_I16:
4055 return assignNew( 'I', pce, Ity_I64, unop(Iop_16Uto64, a) );
4056 case Ity_I32:
4057 return assignNew( 'I', pce, Ity_I64, unop(Iop_32Uto64, a) );
4058 default:
4059 ppIRType(a_ty);
4060 tl_assert(0);
4061 }
4062 }
4063}
4064
4065/* 'e' is a word-sized atom. Call nonptr_or_unknown with it, bind the
4066 results to a new temporary, and return the temporary. Note this
4067 takes an original expression but returns a shadow value. */
4068static IRTemp gen_call_nonptr_or_unknown_w ( PCEnv* pce, IRExpr* e )
4069{
4070 return gen_dirty_W_W( pce, &nonptr_or_unknown,
4071 "nonptr_or_unknown", e );
4072}
4073
4074
4075/* Generate the shadow value for an IRExpr which is an atom and
4076 guaranteed to be word-sized. */
4077static IRAtom* schemeEw_Atom ( PCEnv* pce, IRExpr* e )
4078{
4079 if (pce->gWordTy == Ity_I32) {
4080 if (e->tag == Iex_Const && e->Iex.Const.con->tag == Ico_U32) {
4081 IRTemp t;
4082 tl_assert(sizeof(UWord) == 4);
4083 t = gen_call_nonptr_or_unknown_w(pce, e);
4084 return mkexpr(t);
4085 }
4086 if (e->tag == Iex_RdTmp
sewardje6451332009-07-09 10:45:11 +00004087 && typeOfIRExpr(pce->sb->tyenv, e) == Ity_I32) {
sewardj024598e2008-09-18 14:43:05 +00004088 return mkexpr( findShadowTmp(pce, e->Iex.RdTmp.tmp) );
4089 }
4090 /* there are no other word-sized atom cases */
4091 } else {
4092 if (e->tag == Iex_Const && e->Iex.Const.con->tag == Ico_U64) {
4093 IRTemp t;
4094 tl_assert(sizeof(UWord) == 8);
4095 //return mkU64( (ULong)(UWord)NONPTR );
4096 t = gen_call_nonptr_or_unknown_w(pce, e);
4097 return mkexpr(t);
4098 }
4099 if (e->tag == Iex_RdTmp
sewardje6451332009-07-09 10:45:11 +00004100 && typeOfIRExpr(pce->sb->tyenv, e) == Ity_I64) {
sewardj024598e2008-09-18 14:43:05 +00004101 return mkexpr( findShadowTmp(pce, e->Iex.RdTmp.tmp) );
4102 }
4103 /* there are no other word-sized atom cases */
4104 }
4105 ppIRExpr(e);
4106 tl_assert(0);
4107}
4108
4109
4110static
4111void instrument_arithop ( PCEnv* pce,
4112 IRTemp dst, /* already holds result */
4113 IRTemp dstv, /* generate an assignment to this */
4114 IROp op,
4115 /* original args, guaranteed to be atoms */
4116 IRExpr* a1, IRExpr* a2, IRExpr* a3, IRExpr* a4 )
4117{
4118 HChar* nm = NULL;
4119 void* fn = NULL;
4120 IRExpr* a1v = NULL;
4121 IRExpr* a2v = NULL;
4122 //IRExpr* a3v = NULL;
4123 //IRExpr* a4v = NULL;
4124 IRTemp res = IRTemp_INVALID;
4125
4126 if (pce->gWordTy == Ity_I32) {
4127
4128 tl_assert(pce->hWordTy == Ity_I32);
4129 switch (op) {
4130
4131 /* For these cases, pass Segs for both arguments, and the
4132 result value. */
4133 case Iop_Add32: nm = "do_addW"; fn = &do_addW; goto ssr32;
4134 case Iop_Sub32: nm = "do_subW"; fn = &do_subW; goto ssr32;
4135 case Iop_Or32: nm = "do_orW"; fn = &do_orW; goto ssr32;
4136 ssr32:
4137 a1v = schemeEw_Atom( pce, a1 );
4138 a2v = schemeEw_Atom( pce, a2 );
4139 res = gen_dirty_W_WWW( pce, fn, nm, a1v, a2v, mkexpr(dst) );
4140 assign( 'I', pce, dstv, mkexpr(res) );
4141 break;
4142
4143 /* In this case, pass Segs for both arguments, the result
4144 value, and the difference between the (original) values of
4145 the arguments. */
4146 case Iop_And32:
4147 nm = "do_andW"; fn = &do_andW;
4148 a1v = schemeEw_Atom( pce, a1 );
4149 a2v = schemeEw_Atom( pce, a2 );
4150 res = gen_dirty_W_WWWW(
4151 pce, fn, nm, a1v, a2v, mkexpr(dst),
4152 assignNew( 'I', pce, Ity_I32,
4153 binop(Iop_Sub32,a1,a2) ) );
4154 assign( 'I', pce, dstv, mkexpr(res) );
4155 break;
4156
4157 /* Pass one shadow arg and the result to the helper. */
4158 case Iop_Not32: nm = "do_notW"; fn = &do_notW; goto vr32;
4159 vr32:
4160 a1v = schemeEw_Atom( pce, a1 );
4161 res = gen_dirty_W_WW( pce, fn, nm, a1v, mkexpr(dst) );
4162 assign( 'I', pce, dstv, mkexpr(res) );
4163 break;
4164
4165 /* Pass two shadow args only to the helper. */
4166 case Iop_Mul32: nm = "do_mulW"; fn = &do_mulW; goto vv32;
4167 vv32:
4168 a1v = schemeEw_Atom( pce, a1 );
4169 a2v = schemeEw_Atom( pce, a2 );
4170 res = gen_dirty_W_WW( pce, fn, nm, a1v, a2v );
4171 assign( 'I', pce, dstv, mkexpr(res) );
4172 break;
4173
4174 /* We don't really know what the result could be; test at run
4175 time. */
4176 case Iop_64HIto32: goto n_or_u_32;
4177 case Iop_64to32: goto n_or_u_32;
4178 case Iop_Xor32: goto n_or_u_32;
4179 n_or_u_32:
4180 assign( 'I', pce, dstv,
4181 mkexpr(
4182 gen_call_nonptr_or_unknown_w( pce,
4183 mkexpr(dst) ) ) );
4184 break;
4185
4186 /* Cases where it's very obvious that the result cannot be a
4187 pointer. Hence declare directly that it's NONPTR; don't
4188 bother with the overhead of calling nonptr_or_unknown. */
4189
4190 /* cases where it makes no sense for the result to be a ptr */
4191 /* FIXME: for Shl/Shr/Sar, really should do a test on the 2nd
4192 arg, so that shift by zero preserves the original
4193 value. */
sewardj06f96d02009-12-31 19:24:12 +00004194 case Iop_Shl32: goto n32;
4195 case Iop_Sar32: goto n32;
4196 case Iop_Shr32: goto n32;
4197 case Iop_16Uto32: goto n32;
4198 case Iop_16Sto32: goto n32;
4199 case Iop_F64toI32S: goto n32;
4200 case Iop_16HLto32: goto n32;
4201 case Iop_MullS16: goto n32;
4202 case Iop_MullU16: goto n32;
sewardj024598e2008-09-18 14:43:05 +00004203 case Iop_PRemC3210F64: goto n32;
sewardj06f96d02009-12-31 19:24:12 +00004204 case Iop_DivU32: goto n32;
4205 case Iop_DivS32: goto n32;
4206 case Iop_V128to32: goto n32;
sewardj024598e2008-09-18 14:43:05 +00004207
4208 /* cases where result range is very limited and clearly cannot
4209 be a pointer */
4210 case Iop_1Uto32: goto n32;
4211 case Iop_1Sto32: goto n32;
4212 case Iop_8Uto32: goto n32;
4213 case Iop_8Sto32: goto n32;
4214 case Iop_Clz32: goto n32;
4215 case Iop_Ctz32: goto n32;
4216 case Iop_CmpF64: goto n32;
4217 case Iop_CmpORD32S: goto n32;
4218 case Iop_CmpORD32U: goto n32;
4219 n32:
4220 assign( 'I', pce, dstv, mkU32( (UWord)NONPTR ));
4221 break;
4222
4223 default:
4224 VG_(printf)("instrument_arithop(32-bit): unhandled: ");
4225 ppIROp(op);
4226 tl_assert(0);
4227 }
4228
4229 } else {
4230
4231 tl_assert(pce->gWordTy == Ity_I64);
4232 switch (op) {
4233
4234 /* For these cases, pass Segs for both arguments, and the
4235 result value. */
4236 case Iop_Add64: nm = "do_addW"; fn = &do_addW; goto ssr64;
4237 case Iop_Sub64: nm = "do_subW"; fn = &do_subW; goto ssr64;
4238 case Iop_Or64: nm = "do_orW"; fn = &do_orW; goto ssr64;
4239 ssr64:
4240 a1v = schemeEw_Atom( pce, a1 );
4241 a2v = schemeEw_Atom( pce, a2 );
4242 res = gen_dirty_W_WWW( pce, fn, nm, a1v, a2v, mkexpr(dst) );
4243 assign( 'I', pce, dstv, mkexpr(res) );
4244 break;
4245
4246 /* In this case, pass Segs for both arguments, the result
4247 value, and the difference between the (original) values of
4248 the arguments. */
4249 case Iop_And64:
4250 nm = "do_andW"; fn = &do_andW;
4251 a1v = schemeEw_Atom( pce, a1 );
4252 a2v = schemeEw_Atom( pce, a2 );
4253 res = gen_dirty_W_WWWW(
4254 pce, fn, nm, a1v, a2v, mkexpr(dst),
4255 assignNew( 'I', pce, Ity_I64,
4256 binop(Iop_Sub64,a1,a2) ) );
4257 assign( 'I', pce, dstv, mkexpr(res) );
4258 break;
4259
4260 /* Pass one shadow arg and the result to the helper. */
4261 case Iop_Not64: nm = "do_notW"; fn = &do_notW; goto vr64;
4262 vr64:
4263 a1v = schemeEw_Atom( pce, a1 );
4264 res = gen_dirty_W_WW( pce, fn, nm, a1v, mkexpr(dst) );
4265 assign( 'I', pce, dstv, mkexpr(res) );
4266 break;
4267
4268 /* Pass two shadow args only to the helper. */
4269 case Iop_Mul64: nm = "do_mulW"; fn = &do_mulW; goto vv64;
4270 vv64:
4271 a1v = schemeEw_Atom( pce, a1 );
4272 a2v = schemeEw_Atom( pce, a2 );
4273 res = gen_dirty_W_WW( pce, fn, nm, a1v, a2v );
4274 assign( 'I', pce, dstv, mkexpr(res) );
4275 break;
4276
4277 /* We don't really know what the result could be; test at run
4278 time. */
4279 case Iop_Xor64: goto n_or_u_64;
4280 case Iop_128HIto64: goto n_or_u_64;
4281 case Iop_128to64: goto n_or_u_64;
4282 case Iop_V128HIto64: goto n_or_u_64;
4283 case Iop_V128to64: goto n_or_u_64;
4284 n_or_u_64:
4285 assign( 'I', pce, dstv,
4286 mkexpr(
4287 gen_call_nonptr_or_unknown_w( pce,
4288 mkexpr(dst) ) ) );
4289 break;
4290
4291 /* Cases where it's very obvious that the result cannot be a
4292 pointer. Hence declare directly that it's NONPTR; don't
4293 bother with the overhead of calling nonptr_or_unknown. */
4294
4295 /* cases where it makes no sense for the result to be a ptr */
4296 /* FIXME: for Shl/Shr/Sar, really should do a test on the 2nd
4297 arg, so that shift by zero preserves the original
4298 value. */
4299 case Iop_Shl64: goto n64;
4300 case Iop_Sar64: goto n64;
4301 case Iop_Shr64: goto n64;
4302 case Iop_32Uto64: goto n64;
4303 case Iop_32Sto64: goto n64;
4304 case Iop_16Uto64: goto n64;
4305 case Iop_16Sto64: goto n64;
4306 case Iop_32HLto64: goto n64;
4307 case Iop_DivModU64to32: goto n64;
4308 case Iop_DivModS64to32: goto n64;
sewardj06f96d02009-12-31 19:24:12 +00004309 case Iop_F64toI64S: goto n64;
sewardj024598e2008-09-18 14:43:05 +00004310 case Iop_MullS32: goto n64;
4311 case Iop_MullU32: goto n64;
4312 case Iop_DivU64: goto n64;
4313 case Iop_DivS64: goto n64;
4314 case Iop_ReinterpF64asI64: goto n64;
4315
4316 /* cases where result range is very limited and clearly cannot
4317 be a pointer */
4318 case Iop_1Uto64: goto n64;
4319 case Iop_8Uto64: goto n64;
4320 case Iop_8Sto64: goto n64;
4321 case Iop_Ctz64: goto n64;
4322 case Iop_Clz64: goto n64;
4323 case Iop_CmpORD64S: goto n64;
4324 case Iop_CmpORD64U: goto n64;
4325 /* 64-bit simd */
4326 case Iop_Avg8Ux8: case Iop_Avg16Ux4:
4327 case Iop_Max16Sx4: case Iop_Max8Ux8: case Iop_Min16Sx4:
4328 case Iop_Min8Ux8: case Iop_MulHi16Ux4:
4329 case Iop_QNarrow32Sx2: case Iop_QNarrow16Sx4:
4330 case Iop_QNarrow16Ux4: case Iop_Add8x8: case Iop_Add32x2:
4331 case Iop_QAdd8Sx8: case Iop_QAdd16Sx4: case Iop_QAdd8Ux8:
4332 case Iop_QAdd16Ux4: case Iop_Add16x4: case Iop_CmpEQ8x8:
4333 case Iop_CmpEQ32x2: case Iop_CmpEQ16x4: case Iop_CmpGT8Sx8:
4334 case Iop_CmpGT32Sx2: case Iop_CmpGT16Sx4: case Iop_MulHi16Sx4:
4335 case Iop_Mul16x4: case Iop_ShlN32x2: case Iop_ShlN16x4:
4336 case Iop_SarN32x2: case Iop_SarN16x4: case Iop_ShrN32x2:
4337 case Iop_ShrN16x4: case Iop_Sub8x8: case Iop_Sub32x2:
4338 case Iop_QSub8Sx8: case Iop_QSub16Sx4: case Iop_QSub8Ux8:
4339 case Iop_QSub16Ux4: case Iop_Sub16x4: case Iop_InterleaveHI8x8:
4340 case Iop_InterleaveHI32x2: case Iop_InterleaveHI16x4:
4341 case Iop_InterleaveLO8x8: case Iop_InterleaveLO32x2:
4342 case Iop_InterleaveLO16x4: case Iop_SarN8x8:
4343 case Iop_Perm8x8: case Iop_ShlN8x8: case Iop_Mul32x2:
4344 case Iop_CatEvenLanes16x4: case Iop_CatOddLanes16x4:
4345 n64:
4346 assign( 'I', pce, dstv, mkU64( (UWord)NONPTR ));
4347 break;
4348
4349 default:
4350 VG_(printf)("instrument_arithop(64-bit): unhandled: ");
4351 ppIROp(op);
4352 tl_assert(0);
4353 }
4354 }
4355}
4356
4357static
4358void gen_call_nonptr_or_unknown_range ( PCEnv* pce,
sewardj2d630e22009-07-09 10:52:03 +00004359 IRExpr* guard,
sewardj024598e2008-09-18 14:43:05 +00004360 IRAtom* addr, IRAtom* len )
4361{
sewardj2d630e22009-07-09 10:52:03 +00004362 gen_dirty_v_WW( pce, guard,
sewardj024598e2008-09-18 14:43:05 +00004363 &nonptr_or_unknown_range,
4364 "nonptr_or_unknown_range",
4365 addr, len );
4366}
4367
4368/* iii describes zero or more non-exact integer register updates. For
4369 each one, generate IR to get the containing register, apply
4370 nonptr_or_unknown to it, and write it back again. */
4371static void gen_nonptr_or_unknown_for_III( PCEnv* pce, IntRegInfo* iii )
4372{
4373 Int i;
4374 tl_assert(iii && iii->n_offsets >= 0);
4375 for (i = 0; i < iii->n_offsets; i++) {
4376 IRAtom* a1 = assignNew( 'I', pce, pce->gWordTy,
4377 IRExpr_Get( iii->offsets[i], pce->gWordTy ));
4378 IRTemp a2 = gen_call_nonptr_or_unknown_w( pce, a1 );
4379 stmt( 'I', pce, IRStmt_Put( iii->offsets[i]
4380 + pce->guest_state_sizeB,
4381 mkexpr(a2) ));
4382 }
4383}
4384
sewardjdb5907d2009-11-26 17:20:21 +00004385
4386/* schemeS helper for doing stores, pulled out into a function because
4387 it needs to handle both normal stores and store-conditionals.
4388 Returns False if we see a case we don't know how to handle.
4389*/
4390static Bool schemeS_store ( PCEnv* pce,
4391 IRExpr* data, IRExpr* addr, IRTemp resSC )
4392{
4393 /* We have: STle(addr) = data
4394 if data is int-word sized, do
4395 check_store4(addr, addr#, data, data#)
4396 for all other stores
4397 check_store{1,2}(addr, addr#, data)
4398
4399 The helper actually *does* the store, so that it can do the
4400 post-hoc ugly hack of inspecting and "improving" the shadow data
4401 after the store, in the case where it isn't an aligned word
4402 store.
4403
4404 Only word-sized values are shadowed. If this is a
4405 store-conditional, .resSC will denote a non-word-typed temp, and
4406 so we don't need to shadow it. Assert about the type, tho.
4407 However, since we're not re-emitting the original IRStmt_Store,
4408 but rather doing it as part of the helper function, we need to
4409 actually do a SC in the helper, and assign the result bit to
4410 .resSC. Ugly.
4411 */
4412 IRType d_ty = typeOfIRExpr(pce->sb->tyenv, data);
4413 IRExpr* addrv = schemeEw_Atom( pce, addr );
4414 if (resSC != IRTemp_INVALID) {
4415 tl_assert(typeOfIRTemp(pce->sb->tyenv, resSC) == Ity_I1);
4416 /* viz, not something we want to shadow */
4417 /* also, throw out all store-conditional cases that
4418 we can't handle */
4419 if (pce->gWordTy == Ity_I32 && d_ty != Ity_I32)
4420 return False;
4421 if (pce->gWordTy == Ity_I64 && d_ty != Ity_I32 && d_ty != Ity_I64)
4422 return False;
4423 }
4424 if (pce->gWordTy == Ity_I32) {
4425 /* ------ 32 bit host/guest (cough, cough) ------ */
4426 switch (d_ty) {
4427 /* Integer word case */
4428 case Ity_I32: {
4429 IRExpr* datav = schemeEw_Atom( pce, data );
4430 if (resSC == IRTemp_INVALID) {
4431 /* "normal" store */
4432 gen_dirty_v_WWWW( pce,
4433 &check_store4_P, "check_store4_P",
4434 addr, addrv, data, datav );
4435 } else {
4436 /* store-conditional; need to snarf the success bit */
4437 IRTemp resSC32
4438 = gen_dirty_W_WWWW( pce,
4439 &check_store4C_P,
4440 "check_store4C_P",
4441 addr, addrv, data, datav );
4442 /* presumably resSC32 will really be Ity_I32. In
4443 any case we'll get jumped by the IR sanity
4444 checker if it's not, when it sees the
4445 following statement. */
4446 assign( 'I', pce, resSC, unop(Iop_32to1, mkexpr(resSC32)) );
4447 }
4448 break;
4449 }
4450 /* Integer subword cases */
4451 case Ity_I16:
4452 gen_dirty_v_WWW( pce,
4453 &check_store2, "check_store2",
4454 addr, addrv,
4455 uwiden_to_host_word( pce, data ));
4456 break;
4457 case Ity_I8:
4458 gen_dirty_v_WWW( pce,
4459 &check_store1, "check_store1",
4460 addr, addrv,
4461 uwiden_to_host_word( pce, data ));
4462 break;
4463 /* 64-bit float. Pass store data in 2 32-bit pieces. */
4464 case Ity_F64: {
4465 IRAtom* d64 = assignNew( 'I', pce, Ity_I64,
4466 unop(Iop_ReinterpF64asI64, data) );
4467 IRAtom* dLo32 = assignNew( 'I', pce, Ity_I32,
4468 unop(Iop_64to32, d64) );
4469 IRAtom* dHi32 = assignNew( 'I', pce, Ity_I32,
4470 unop(Iop_64HIto32, d64) );
4471 gen_dirty_v_WWWW( pce,
4472 &check_store8_ms4B_ls4B,
4473 "check_store8_ms4B_ls4B",
4474 addr, addrv, dHi32, dLo32 );
4475 break;
4476 }
4477 /* 32-bit float. We can just use _store4, but need
4478 to futz with the argument type. */
4479 case Ity_F32: {
4480 IRAtom* i32 = assignNew( 'I', pce, Ity_I32,
4481 unop(Iop_ReinterpF32asI32,
4482 data ) );
4483 gen_dirty_v_WWW( pce,
4484 &check_store4,
4485 "check_store4",
4486 addr, addrv, i32 );
4487 break;
4488 }
4489 /* 64-bit int. Pass store data in 2 32-bit pieces. */
4490 case Ity_I64: {
4491 IRAtom* dLo32 = assignNew( 'I', pce, Ity_I32,
4492 unop(Iop_64to32, data) );
4493 IRAtom* dHi32 = assignNew( 'I', pce, Ity_I32,
4494 unop(Iop_64HIto32, data) );
4495 gen_dirty_v_WWWW( pce,
4496 &check_store8_ms4B_ls4B,
4497 "check_store8_ms4B_ls4B",
4498 addr, addrv, dHi32, dLo32 );
4499 break;
4500 }
4501 /* 128-bit vector. Pass store data in 4 32-bit pieces.
4502 This is all very ugly and inefficient, but it is
4503 hard to better without considerably complicating the
4504 store-handling schemes. */
4505 case Ity_V128: {
4506 IRAtom* dHi64 = assignNew( 'I', pce, Ity_I64,
4507 unop(Iop_V128HIto64, data) );
4508 IRAtom* dLo64 = assignNew( 'I', pce, Ity_I64,
4509 unop(Iop_V128to64, data) );
4510 IRAtom* w3 = assignNew( 'I', pce, Ity_I32,
4511 unop(Iop_64HIto32, dHi64) );
4512 IRAtom* w2 = assignNew( 'I', pce, Ity_I32,
4513 unop(Iop_64to32, dHi64) );
4514 IRAtom* w1 = assignNew( 'I', pce, Ity_I32,
4515 unop(Iop_64HIto32, dLo64) );
4516 IRAtom* w0 = assignNew( 'I', pce, Ity_I32,
4517 unop(Iop_64to32, dLo64) );
4518 gen_dirty_v_6W( pce,
4519 &check_store16_ms4B_4B_4B_ls4B,
4520 "check_store16_ms4B_4B_4B_ls4B",
4521 addr, addrv, w3, w2, w1, w0 );
4522 break;
4523 }
4524 default:
4525 ppIRType(d_ty); tl_assert(0);
4526 }
4527 } else {
4528 /* ------ 64 bit host/guest (cough, cough) ------ */
4529 switch (d_ty) {
4530 /* Integer word case */
4531 case Ity_I64: {
4532 IRExpr* datav = schemeEw_Atom( pce, data );
4533 if (resSC == IRTemp_INVALID) {
4534 /* "normal" store */
4535 gen_dirty_v_WWWW( pce,
4536 &check_store8_P, "check_store8_P",
4537 addr, addrv, data, datav );
4538 } else {
4539 IRTemp resSC64
4540 = gen_dirty_W_WWWW( pce,
4541 &check_store8C_P,
4542 "check_store8C_P",
4543 addr, addrv, data, datav );
4544 assign( 'I', pce, resSC, unop(Iop_64to1, mkexpr(resSC64)) );
4545 }
4546 break;
4547 }
4548 /* Integer subword cases */
4549 case Ity_I32:
4550 if (resSC == IRTemp_INVALID) {
4551 /* "normal" store */
4552 gen_dirty_v_WWW( pce,
4553 &check_store4, "check_store4",
4554 addr, addrv,
4555 uwiden_to_host_word( pce, data ));
4556 } else {
4557 /* store-conditional; need to snarf the success bit */
4558 IRTemp resSC64
4559 = gen_dirty_W_WWW( pce,
4560 &check_store4C,
4561 "check_store4C",
4562 addr, addrv,
4563 uwiden_to_host_word( pce, data ));
4564 assign( 'I', pce, resSC, unop(Iop_64to1, mkexpr(resSC64)) );
4565 }
4566 break;
4567 case Ity_I16:
4568 gen_dirty_v_WWW( pce,
4569 &check_store2, "check_store2",
4570 addr, addrv,
4571 uwiden_to_host_word( pce, data ));
4572 break;
4573 case Ity_I8:
4574 gen_dirty_v_WWW( pce,
4575 &check_store1, "check_store1",
4576 addr, addrv,
4577 uwiden_to_host_word( pce, data ));
4578 break;
4579 /* 128-bit vector. Pass store data in 2 64-bit pieces. */
4580 case Ity_V128: {
4581 IRAtom* dHi64 = assignNew( 'I', pce, Ity_I64,
4582 unop(Iop_V128HIto64, data) );
4583 IRAtom* dLo64 = assignNew( 'I', pce, Ity_I64,
4584 unop(Iop_V128to64, data) );
4585 gen_dirty_v_WWWW( pce,
4586 &check_store16_ms8B_ls8B,
4587 "check_store16_ms8B_ls8B",
4588 addr, addrv, dHi64, dLo64 );
4589 break;
4590 }
4591 /* 64-bit float. */
4592 case Ity_F64: {
4593 IRAtom* dI = assignNew( 'I', pce, Ity_I64,
4594 unop(Iop_ReinterpF64asI64,
4595 data ) );
4596 gen_dirty_v_WWW( pce,
4597 &check_store8_all8B,
4598 "check_store8_all8B",
4599 addr, addrv, dI );
4600 break;
4601 }
4602 /* 32-bit float. We can just use _store4, but need
4603 to futz with the argument type. */
4604 case Ity_F32: {
4605 IRAtom* i32 = assignNew( 'I', pce, Ity_I32,
4606 unop(Iop_ReinterpF32asI32,
4607 data ) );
4608 IRAtom* i64 = assignNew( 'I', pce, Ity_I64,
4609 unop(Iop_32Uto64,
4610 i32 ) );
4611 gen_dirty_v_WWW( pce,
4612 &check_store4,
4613 "check_store4",
4614 addr, addrv, i64 );
4615 break;
4616 }
4617 default:
4618 ppIRType(d_ty); tl_assert(0);
4619 }
4620 }
4621 /* And don't copy the original, since the helper does the store.
4622 Ick. */
4623 return True; /* store was successfully instrumented */
4624}
4625
4626
4627/* schemeS helper for doing loads, pulled out into a function because
4628 it needs to handle both normal loads and load-linked's.
4629*/
4630static void schemeS_load ( PCEnv* pce, IRExpr* addr, IRType e_ty, IRTemp dstv )
4631{
4632 HChar* h_nm = NULL;
4633 void* h_fn = NULL;
4634 IRExpr* addrv = NULL;
4635 if (e_ty == pce->gWordTy) {
4636 tl_assert(dstv != IRTemp_INVALID);
4637 } else {
4638 tl_assert(dstv == IRTemp_INVALID);
4639 }
4640 if (pce->gWordTy == Ity_I32) {
4641 /* 32 bit host/guest (cough, cough) */
4642 switch (e_ty) {
4643 /* Ity_I32: helper returns shadow value. */
4644 case Ity_I32: h_fn = &check_load4_P;
4645 h_nm = "check_load4_P"; break;
4646 /* all others: helper does not return a shadow
4647 value. */
4648 case Ity_V128: h_fn = &check_load16;
4649 h_nm = "check_load16"; break;
4650 case Ity_I64:
4651 case Ity_F64: h_fn = &check_load8;
4652 h_nm = "check_load8"; break;
4653 case Ity_F32: h_fn = &check_load4;
4654 h_nm = "check_load4"; break;
4655 case Ity_I16: h_fn = &check_load2;
4656 h_nm = "check_load2"; break;
4657 case Ity_I8: h_fn = &check_load1;
4658 h_nm = "check_load1"; break;
4659 default: ppIRType(e_ty); tl_assert(0);
4660 }
4661 addrv = schemeEw_Atom( pce, addr );
4662 if (e_ty == Ity_I32) {
4663 assign( 'I', pce, dstv,
4664 mkexpr( gen_dirty_W_WW( pce, h_fn, h_nm,
4665 addr, addrv )) );
4666 } else {
4667 gen_dirty_v_WW( pce, NULL, h_fn, h_nm, addr, addrv );
4668 }
4669 } else {
4670 /* 64 bit host/guest (cough, cough) */
4671 switch (e_ty) {
4672 /* Ity_I64: helper returns shadow value. */
4673 case Ity_I64: h_fn = &check_load8_P;
4674 h_nm = "check_load8_P"; break;
4675 /* all others: helper does not return a shadow
4676 value. */
4677 case Ity_V128: h_fn = &check_load16;
4678 h_nm = "check_load16"; break;
4679 case Ity_F64: h_fn = &check_load8;
4680 h_nm = "check_load8"; break;
4681 case Ity_F32:
4682 case Ity_I32: h_fn = &check_load4;
4683 h_nm = "check_load4"; break;
4684 case Ity_I16: h_fn = &check_load2;
4685 h_nm = "check_load2"; break;
4686 case Ity_I8: h_fn = &check_load1;
4687 h_nm = "check_load1"; break;
4688 default: ppIRType(e_ty); tl_assert(0);
4689 }
4690 addrv = schemeEw_Atom( pce, addr );
4691 if (e_ty == Ity_I64) {
4692 assign( 'I', pce, dstv,
4693 mkexpr( gen_dirty_W_WW( pce, h_fn, h_nm,
4694 addr, addrv )) );
4695 } else {
4696 gen_dirty_v_WW( pce, NULL, h_fn, h_nm, addr, addrv );
4697 }
4698 }
4699}
4700
4701
sewardj1c0ce7a2009-07-01 08:10:49 +00004702/* Generate into 'pce', instrumentation for 'st'. Also copy 'st'
4703 itself into 'pce' (the caller does not do so). This is somewhat
sewardj024598e2008-09-18 14:43:05 +00004704 complex and relies heavily on the assumption that the incoming IR
4705 is in flat form.
4706
4707 Generally speaking, the instrumentation is placed after the
4708 original statement, so that results computed by the original can be
4709 used in the instrumentation. However, that isn't safe for memory
4710 references, since we need the instrumentation (hence bounds check
4711 and potential error message) to happen before the reference itself,
4712 as the latter could cause a fault. */
4713static void schemeS ( PCEnv* pce, IRStmt* st )
4714{
4715 tl_assert(st);
4716 tl_assert(isFlatIRStmt(st));
4717
4718 switch (st->tag) {
4719
sewardj2d630e22009-07-09 10:52:03 +00004720 case Ist_CAS: {
sewardjafed4c52009-07-12 13:00:17 +00004721 /* In all these CAS cases, the did-we-succeed? comparison is
4722 done using Iop_CasCmpEQ{8,16,32,64} rather than the plain
4723 Iop_CmpEQ equivalents. This isn't actually necessary,
4724 since the generated IR is not going to be subsequently
4725 instrumented by Memcheck. But it's done for consistency.
4726 See COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
4727 background/rationale. */
sewardj2d630e22009-07-09 10:52:03 +00004728 IRCAS* cas = st->Ist.CAS.details;
4729 IRType elTy = typeOfIRExpr(pce->sb->tyenv, cas->expdLo);
4730 if (cas->oldHi == IRTemp_INVALID) {
4731 /* ------------ SINGLE CAS ------------ */
4732 /* -- single cas -- 32 bits, on 32-bit host -- */
4733 /* -- single cas -- 64 bits, on 64-bit host -- */
4734 /* -- viz, single cas, native-word case -- */
4735 if ( (pce->gWordTy == Ity_I32 && elTy == Ity_I32)
4736 || (pce->gWordTy == Ity_I64 && elTy == Ity_I64) ) {
4737 // 32 bit host translation scheme; 64-bit is analogous
4738 // old# = check_load4_P(addr, addr#)
4739 // old = CAS(addr:expd->new) [COPY]
sewardjafed4c52009-07-12 13:00:17 +00004740 // success = CasCmpEQ32(old,expd)
sewardj2d630e22009-07-09 10:52:03 +00004741 // if (success) do_shadow_store4_P(addr, new#)
4742 IRTemp success;
4743 Bool is64 = elTy == Ity_I64;
sewardjafed4c52009-07-12 13:00:17 +00004744 IROp cmpEQ = is64 ? Iop_CasCmpEQ64 : Iop_CasCmpEQ32;
sewardj2d630e22009-07-09 10:52:03 +00004745 void* r_fn = is64 ? &check_load8_P : &check_load4_P;
4746 HChar* r_nm = is64 ? "check_load8_P" : "check_load4_P";
4747 void* w_fn = is64 ? &do_shadow_store8_P : &do_shadow_store4_P;
4748 void* w_nm = is64 ? "do_shadow_store8_P" : "do_shadow_store4_P";
4749 IRExpr* addr = cas->addr;
4750 IRExpr* addrV = schemeEw_Atom(pce, addr);
4751 IRTemp old = cas->oldLo;
4752 IRTemp oldV = newShadowTmp(pce, old);
4753 IRExpr* nyu = cas->dataLo;
4754 IRExpr* nyuV = schemeEw_Atom(pce, nyu);
4755 IRExpr* expd = cas->expdLo;
4756 assign( 'I', pce, oldV,
4757 mkexpr( gen_dirty_W_WW( pce, r_fn, r_nm, addr, addrV )));
4758 stmt( 'C', pce, st );
4759 success = newTemp(pce, Ity_I1, NonShad);
4760 assign('I', pce, success, binop(cmpEQ, mkexpr(old), expd));
4761 gen_dirty_v_WW( pce, mkexpr(success), w_fn, w_nm, addr, nyuV );
4762 }
4763 else
4764 /* -- single cas -- 8 or 16 bits, on 32-bit host -- */
4765 /* -- viz, single cas, 32-bit subword cases -- */
4766 if (pce->gWordTy == Ity_I32
4767 && (elTy == Ity_I8 || elTy == Ity_I16)) {
4768 // 8-bit translation scheme; 16-bit is analogous
4769 // check_load1(addr, addr#)
4770 // old = CAS(addr:expd->new) [COPY]
sewardjafed4c52009-07-12 13:00:17 +00004771 // success = CasCmpEQ8(old,expd)
sewardj2d630e22009-07-09 10:52:03 +00004772 // if (success) nonptr_or_unknown_range(addr, 1)
4773 IRTemp success;
4774 Bool is16 = elTy == Ity_I16;
4775 IRExpr* addr = cas->addr;
4776 IRExpr* addrV = schemeEw_Atom(pce, addr);
4777 IRTemp old = cas->oldLo;
4778 IRExpr* expd = cas->expdLo;
4779 void* h_fn = is16 ? &check_load2 : &check_load1;
4780 HChar* h_nm = is16 ? "check_load2" : "check_load1";
sewardjafed4c52009-07-12 13:00:17 +00004781 IROp cmpEQ = is16 ? Iop_CasCmpEQ16 : Iop_CasCmpEQ8;
sewardj2d630e22009-07-09 10:52:03 +00004782 Int szB = is16 ? 2 : 1;
4783 gen_dirty_v_WW( pce, NULL, h_fn, h_nm, addr, addrV );
4784 stmt( 'C', pce, st );
4785 success = newTemp(pce, Ity_I1, NonShad);
4786 assign('I', pce, success,
4787 binop(cmpEQ, mkexpr(old), expd));
4788 gen_call_nonptr_or_unknown_range( pce, mkexpr(success),
4789 addr, mkIRExpr_HWord(szB) );
4790 }
4791 else
4792 /* -- single cas -- 8, 16 or 32 bits, on 64-bit host -- */
4793 /* -- viz, single cas, 64-bit subword cases -- */
4794 if (pce->gWordTy == Ity_I64
4795 && (elTy == Ity_I8 || elTy == Ity_I16 || elTy == Ity_I32)) {
4796 // 8-bit translation scheme; 16/32-bit are analogous
4797 // check_load1(addr, addr#)
4798 // old = CAS(addr:expd->new) [COPY]
sewardjafed4c52009-07-12 13:00:17 +00004799 // success = CasCmpEQ8(old,expd)
sewardj2d630e22009-07-09 10:52:03 +00004800 // if (success) nonptr_or_unknown_range(addr, 1)
4801 IRTemp success;
4802 Bool is16 = elTy == Ity_I16;
4803 Bool is32 = elTy == Ity_I32;
4804 IRExpr* addr = cas->addr;
4805 IRExpr* addrV = schemeEw_Atom(pce, addr);
4806 IRTemp old = cas->oldLo;
4807 IRExpr* expd = cas->expdLo;
4808 void* h_fn = is32 ? &check_load4
4809 : (is16 ? &check_load2 : &check_load1);
4810 HChar* h_nm = is32 ? "check_load4"
4811 : (is16 ? "check_load2" : "check_load1");
sewardjafed4c52009-07-12 13:00:17 +00004812 IROp cmpEQ = is32 ? Iop_CasCmpEQ32
4813 : (is16 ? Iop_CasCmpEQ16 : Iop_CasCmpEQ8);
sewardj2d630e22009-07-09 10:52:03 +00004814 Int szB = is32 ? 4 : (is16 ? 2 : 1);
4815 gen_dirty_v_WW( pce, NULL, h_fn, h_nm, addr, addrV );
4816 stmt( 'C', pce, st );
4817 success = newTemp(pce, Ity_I1, NonShad);
4818 assign('I', pce, success,
4819 binop(cmpEQ, mkexpr(old), expd));
4820 gen_call_nonptr_or_unknown_range( pce, mkexpr(success),
4821 addr, mkIRExpr_HWord(szB) );
4822 }
4823 else
4824 goto unhandled;
4825 } else {
4826 /* ------------ DOUBLE CAS ------------ */
4827 /* Punt on bigendian DCAS. In fact it's probably trivial
4828 to do; just swap the individual shadow loads/stores
4829 around in memory, but we'd have to verify it, and there
4830 is no use case. So punt. */
4831 if (cas->end != Iend_LE)
4832 goto unhandled;
4833 /* -- double cas -- 2 x 32 bits, on 32-bit host -- */
4834 /* -- double cas -- 2 x 64 bits, on 64-bit host -- */
4835 /* -- viz, double cas, native-word case -- */
4836 if ( (pce->gWordTy == Ity_I32 && elTy == Ity_I32)
4837 || (pce->gWordTy == Ity_I64 && elTy == Ity_I64) ) {
4838 // 32 bit host translation scheme; 64-bit is analogous
4839 // oldHi# = check_load4_P(addr+4, addr#)
4840 // oldLo# = check_load4_P(addr+0, addr#)
4841 // oldHi/Lo = DCAS(addr:expdHi/Lo->newHi/Lo) [COPY]
sewardjafed4c52009-07-12 13:00:17 +00004842 // success = CasCmpEQ32(oldHi,expdHi) && CasCmpEQ32(oldLo,expdLo)
sewardj2d630e22009-07-09 10:52:03 +00004843 // = ((oldHi ^ expdHi) | (oldLo ^ expdLo)) == 0
4844 // if (success) do_shadow_store4_P(addr+4, newHi#)
4845 // if (success) do_shadow_store4_P(addr+0, newLo#)
4846 IRTemp diffHi, diffLo, diff, success, addrpp;
sewardjafed4c52009-07-12 13:00:17 +00004847 Bool is64 = elTy == Ity_I64;
4848 void* r_fn = is64 ? &check_load8_P : &check_load4_P;
4849 HChar* r_nm = is64 ? "check_load8_P" : "check_load4_P";
4850 void* w_fn = is64 ? &do_shadow_store8_P
4851 : &do_shadow_store4_P;
4852 void* w_nm = is64 ? "do_shadow_store8_P"
4853 : "do_shadow_store4_P";
4854 IROp opADD = is64 ? Iop_Add64 : Iop_Add32;
4855 IROp opXOR = is64 ? Iop_Xor64 : Iop_Xor32;
4856 IROp opOR = is64 ? Iop_Or64 : Iop_Or32;
4857 IROp opCasCmpEQ = is64 ? Iop_CasCmpEQ64 : Iop_CasCmpEQ32;
4858 IRExpr* step = is64 ? mkU64(8) : mkU32(4);
4859 IRExpr* zero = is64 ? mkU64(0) : mkU32(0);
4860 IRExpr* addr = cas->addr;
4861 IRExpr* addrV = schemeEw_Atom(pce, addr);
4862 IRTemp oldLo = cas->oldLo;
4863 IRTemp oldLoV = newShadowTmp(pce, oldLo);
4864 IRTemp oldHi = cas->oldHi;
4865 IRTemp oldHiV = newShadowTmp(pce, oldHi);
4866 IRExpr* nyuLo = cas->dataLo;
4867 IRExpr* nyuLoV = schemeEw_Atom(pce, nyuLo);
4868 IRExpr* nyuHi = cas->dataHi;
4869 IRExpr* nyuHiV = schemeEw_Atom(pce, nyuHi);
4870 IRExpr* expdLo = cas->expdLo;
4871 IRExpr* expdHi = cas->expdHi;
sewardj2d630e22009-07-09 10:52:03 +00004872 tl_assert(elTy == Ity_I32 || elTy == Ity_I64);
4873 tl_assert(pce->gWordTy == elTy);
4874 addrpp = newTemp(pce, elTy, NonShad);
4875 assign('I', pce, addrpp, binop(opADD, addr, step));
4876 assign('I', pce, oldHiV,
4877 mkexpr( gen_dirty_W_WW( pce, r_fn, r_nm,
4878 mkexpr(addrpp), addrV ))
4879 );
4880 assign('I', pce, oldLoV,
4881 mkexpr( gen_dirty_W_WW( pce, r_fn, r_nm,
4882 addr, addrV ))
4883 );
4884 stmt( 'C', pce, st );
4885 diffHi = newTemp(pce, elTy, NonShad);
4886 assign('I', pce, diffHi,
4887 binop(opXOR, mkexpr(oldHi), expdHi));
4888 diffLo = newTemp(pce, elTy, NonShad);
4889 assign('I', pce, diffLo,
4890 binop(opXOR, mkexpr(oldLo), expdLo));
4891 diff = newTemp(pce, elTy, NonShad);
4892 assign('I', pce, diff,
4893 binop(opOR, mkexpr(diffHi), mkexpr(diffLo)));
4894 success = newTemp(pce, Ity_I1, NonShad);
4895 assign('I', pce, success,
sewardjafed4c52009-07-12 13:00:17 +00004896 binop(opCasCmpEQ, mkexpr(diff), zero));
sewardj2d630e22009-07-09 10:52:03 +00004897 gen_dirty_v_WW( pce, mkexpr(success),
4898 w_fn, w_nm, mkexpr(addrpp), nyuHiV );
4899 gen_dirty_v_WW( pce, mkexpr(success),
4900 w_fn, w_nm, addr, nyuLoV );
4901 }
4902 else
4903 /* -- double cas -- 2 x 32 bits, on 64-bit host -- */
4904 if (pce->gWordTy == Ity_I64 && elTy == Ity_I32) {
4905 // check_load8(addr, addr#)
4906 // oldHi/Lo = DCAS(addr:expdHi/Lo->newHi/Lo) [COPY]
sewardjafed4c52009-07-12 13:00:17 +00004907 // success = CasCmpEQ32(oldHi,expdHi) && CasCmpEQ32(oldLo,expdLo)
sewardj2d630e22009-07-09 10:52:03 +00004908 // = ((oldHi ^ expdHi) | (oldLo ^ expdLo)) == 0
4909 // if (success) nonptr_or_unknown_range(addr, 8)
4910 IRTemp diffHi, diffLo, diff, success;
4911 IRExpr* addr = cas->addr;
4912 IRExpr* addrV = schemeEw_Atom(pce, addr);
4913 IRTemp oldLo = cas->oldLo;
4914 IRTemp oldHi = cas->oldHi;
4915 IRExpr* expdLo = cas->expdLo;
4916 IRExpr* expdHi = cas->expdHi;
4917 gen_dirty_v_WW( pce, NULL, &check_load8, "check_load8",
4918 addr, addrV );
4919 stmt( 'C', pce, st );
4920 diffHi = newTemp(pce, Ity_I32, NonShad);
4921 assign('I', pce, diffHi,
4922 binop(Iop_Xor32, mkexpr(oldHi), expdHi));
4923 diffLo = newTemp(pce, Ity_I32, NonShad);
4924 assign('I', pce, diffLo,
4925 binop(Iop_Xor32, mkexpr(oldLo), expdLo));
4926 diff = newTemp(pce, Ity_I32, NonShad);
4927 assign('I', pce, diff,
4928 binop(Iop_Or32, mkexpr(diffHi), mkexpr(diffLo)));
4929 success = newTemp(pce, Ity_I1, NonShad);
4930 assign('I', pce, success,
sewardjafed4c52009-07-12 13:00:17 +00004931 binop(Iop_CasCmpEQ32, mkexpr(diff), mkU32(0)));
sewardj2d630e22009-07-09 10:52:03 +00004932 gen_call_nonptr_or_unknown_range( pce, mkexpr(success),
4933 addr, mkU64(8) );
4934 }
4935 else
4936 goto unhandled;
4937 }
4938 break;
4939 }
4940
sewardjdb5907d2009-11-26 17:20:21 +00004941 case Ist_LLSC: {
4942 if (st->Ist.LLSC.storedata == NULL) {
4943 /* LL */
4944 IRTemp dst = st->Ist.LLSC.result;
4945 IRType dataTy = typeOfIRTemp(pce->sb->tyenv, dst);
4946 Bool isWord = dataTy == pce->gWordTy;
4947 IRTemp dstv = isWord ? newShadowTmp( pce, dst )
4948 : IRTemp_INVALID;
4949 schemeS_load( pce, st->Ist.LLSC.addr, dataTy, dstv );
4950 /* copy the original -- must happen after the helper call */
4951 stmt( 'C', pce, st );
4952 } else {
4953 /* SC */
4954 schemeS_store( pce,
4955 st->Ist.LLSC.storedata,
4956 st->Ist.LLSC.addr,
4957 st->Ist.LLSC.result );
4958 /* Don't copy the original, since the helper does the
4959 store itself. */
4960 }
4961 break;
4962 }
4963
sewardj024598e2008-09-18 14:43:05 +00004964 case Ist_Dirty: {
4965 Int i;
4966 IRDirty* di;
4967 stmt( 'C', pce, st );
4968 /* nasty. assumes that (1) all helpers are unconditional,
4969 and (2) all outputs are non-ptr */
4970 di = st->Ist.Dirty.details;
4971 /* deal with the return tmp, if any */
4972 if (di->tmp != IRTemp_INVALID
sewardje6451332009-07-09 10:45:11 +00004973 && typeOfIRTemp(pce->sb->tyenv, di->tmp) == pce->gWordTy) {
sewardj024598e2008-09-18 14:43:05 +00004974 /* di->tmp is shadowed. Set it to NONPTR. */
4975 IRTemp dstv = newShadowTmp( pce, di->tmp );
4976 if (pce->gWordTy == Ity_I32) {
4977 assign( 'I', pce, dstv, mkU32( (UWord)NONPTR ));
4978 } else {
4979 assign( 'I', pce, dstv, mkU64( (UWord)NONPTR ));
4980 }
4981 }
4982 /* apply the nonptr_or_unknown technique to any parts of
4983 the guest state that happen to get written */
4984 for (i = 0; i < di->nFxState; i++) {
4985 IntRegInfo iii;
4986 tl_assert(di->fxState[i].fx != Ifx_None);
4987 if (di->fxState[i].fx == Ifx_Read)
4988 continue; /* this bit is only read -- not interesting */
4989 get_IntRegInfo( &iii, di->fxState[i].offset,
4990 di->fxState[i].size );
4991 tl_assert(iii.n_offsets >= -1
4992 && iii.n_offsets <= N_INTREGINFO_OFFSETS);
4993 /* Deal with 3 possible cases, same as with Ist_Put
4994 elsewhere in this function. */
4995 if (iii.n_offsets == -1) {
4996 /* case (1): exact write of an integer register. */
4997 IRAtom* a1
4998 = assignNew( 'I', pce, pce->gWordTy,
4999 IRExpr_Get( iii.offsets[i], pce->gWordTy ));
5000 IRTemp a2 = gen_call_nonptr_or_unknown_w( pce, a1 );
5001 stmt( 'I', pce, IRStmt_Put( iii.offsets[i]
5002 + pce->guest_state_sizeB,
5003 mkexpr(a2) ));
5004 } else {
5005 /* when == 0: case (3): no instrumentation needed */
5006 /* when > 0: case (2) .. complex case. Fish out the
5007 stored value for the whole register, heave it
5008 through nonptr_or_unknown, and use that as the new
5009 shadow value. */
5010 tl_assert(iii.n_offsets >= 0
5011 && iii.n_offsets <= N_INTREGINFO_OFFSETS);
5012 gen_nonptr_or_unknown_for_III( pce, &iii );
5013 }
5014 } /* for (i = 0; i < di->nFxState; i++) */
5015 /* finally, deal with memory outputs */
5016 if (di->mFx != Ifx_None) {
5017 tl_assert(di->mAddr && isIRAtom(di->mAddr));
5018 tl_assert(di->mSize > 0);
sewardj2d630e22009-07-09 10:52:03 +00005019 gen_call_nonptr_or_unknown_range( pce, NULL, di->mAddr,
sewardj024598e2008-09-18 14:43:05 +00005020 mkIRExpr_HWord(di->mSize));
5021 }
5022 break;
5023 }
5024
5025 case Ist_NoOp:
5026 break;
5027
5028 /* nothing interesting in these; just copy them through */
5029 case Ist_AbiHint:
5030 case Ist_MBE:
5031 case Ist_Exit:
5032 case Ist_IMark:
5033 stmt( 'C', pce, st );
5034 break;
5035
5036 case Ist_PutI: {
5037 IRRegArray* descr = st->Ist.PutI.descr;
5038 stmt( 'C', pce, st );
5039 tl_assert(descr && descr->elemTy);
5040 if (is_integer_guest_reg_array(descr)) {
5041 /* if this fails, is_integer_guest_reg_array is returning
5042 bogus results */
5043 tl_assert(descr->elemTy == pce->gWordTy);
5044 stmt(
5045 'I', pce,
5046 IRStmt_PutI(
5047 mkIRRegArray(descr->base + pce->guest_state_sizeB,
5048 descr->elemTy, descr->nElems),
5049 st->Ist.PutI.ix,
5050 st->Ist.PutI.bias,
5051 schemeEw_Atom( pce, st->Ist.PutI.data)
5052 )
5053 );
5054 }
5055 break;
5056 }
5057
5058 case Ist_Put: {
5059 /* PUT(offset) = atom */
5060 /* 3 cases:
5061 1. It's a complete write of an integer register. Get hold of
5062 'atom's shadow value and write it in the shadow state.
5063 2. It's a partial write of an integer register. Let the write
5064 happen, then fish out the complete register value and see if,
5065 via range checking, consultation of tea leaves, etc, its
5066 shadow value can be upgraded to anything useful.
5067 3. It is none of the above. Generate no instrumentation. */
5068 IntRegInfo iii;
5069 IRType ty;
5070 stmt( 'C', pce, st );
sewardje6451332009-07-09 10:45:11 +00005071 ty = typeOfIRExpr(pce->sb->tyenv, st->Ist.Put.data);
sewardj024598e2008-09-18 14:43:05 +00005072 get_IntRegInfo( &iii, st->Ist.Put.offset,
5073 sizeofIRType(ty) );
5074 if (iii.n_offsets == -1) {
5075 /* case (1): exact write of an integer register. */
5076 tl_assert(ty == pce->gWordTy);
5077 stmt( 'I', pce,
5078 IRStmt_Put( st->Ist.Put.offset
5079 + pce->guest_state_sizeB,
5080 schemeEw_Atom( pce, st->Ist.Put.data)) );
5081 } else {
5082 /* when == 0: case (3): no instrumentation needed */
5083 /* when > 0: case (2) .. complex case. Fish out the
5084 stored value for the whole register, heave it through
5085 nonptr_or_unknown, and use that as the new shadow
5086 value. */
5087 tl_assert(iii.n_offsets >= 0
5088 && iii.n_offsets <= N_INTREGINFO_OFFSETS);
5089 gen_nonptr_or_unknown_for_III( pce, &iii );
5090 }
5091 break;
5092 } /* case Ist_Put */
5093
5094 case Ist_Store: {
sewardjdb5907d2009-11-26 17:20:21 +00005095 Bool ok = schemeS_store( pce,
5096 st->Ist.Store.data,
5097 st->Ist.Store.addr,
5098 IRTemp_INVALID/*not a SC*/ );
5099 if (!ok) goto unhandled;
5100 /* Don't copy the original, since the helper does the store
5101 itself. */
sewardj024598e2008-09-18 14:43:05 +00005102 break;
sewardjdb5907d2009-11-26 17:20:21 +00005103 }
sewardj024598e2008-09-18 14:43:05 +00005104
5105 case Ist_WrTmp: {
5106 /* This is the only place we have to deal with the full
5107 IRExpr range. In all other places where an IRExpr could
5108 appear, we in fact only get an atom (Iex_RdTmp or
5109 Iex_Const). */
5110 IRExpr* e = st->Ist.WrTmp.data;
sewardje6451332009-07-09 10:45:11 +00005111 IRType e_ty = typeOfIRExpr( pce->sb->tyenv, e );
sewardj024598e2008-09-18 14:43:05 +00005112 Bool isWord = e_ty == pce->gWordTy;
5113 IRTemp dst = st->Ist.WrTmp.tmp;
5114 IRTemp dstv = isWord ? newShadowTmp( pce, dst )
5115 : IRTemp_INVALID;
5116
5117 switch (e->tag) {
5118
5119 case Iex_Const: {
5120 stmt( 'C', pce, st );
5121 if (isWord)
5122 assign( 'I', pce, dstv, schemeEw_Atom( pce, e ) );
5123 break;
5124 }
5125
5126 case Iex_CCall: {
5127 stmt( 'C', pce, st );
5128 if (isWord)
5129 assign( 'I', pce, dstv,
5130 mkexpr( gen_call_nonptr_or_unknown_w(
5131 pce, mkexpr(dst))));
5132 break;
5133 }
5134
5135 case Iex_Mux0X: {
5136 /* Just steer the shadow values in the same way as the
5137 originals. */
5138 stmt( 'C', pce, st );
5139 if (isWord)
5140 assign( 'I', pce, dstv,
5141 IRExpr_Mux0X(
5142 e->Iex.Mux0X.cond,
5143 schemeEw_Atom( pce, e->Iex.Mux0X.expr0 ),
5144 schemeEw_Atom( pce, e->Iex.Mux0X.exprX ) ));
5145 break;
5146 }
5147
5148 case Iex_RdTmp: {
5149 stmt( 'C', pce, st );
5150 if (isWord)
5151 assign( 'I', pce, dstv, schemeEw_Atom( pce, e ));
5152 break;
5153 }
5154
5155 case Iex_Load: {
sewardjdb5907d2009-11-26 17:20:21 +00005156 schemeS_load( pce, e->Iex.Load.addr, e_ty, dstv );
sewardj024598e2008-09-18 14:43:05 +00005157 /* copy the original -- must happen after the helper call */
5158 stmt( 'C', pce, st );
5159 break;
5160 }
5161
5162 case Iex_GetI: {
5163 IRRegArray* descr = e->Iex.GetI.descr;
5164 stmt( 'C', pce, st );
5165 tl_assert(descr && descr->elemTy);
5166 if (is_integer_guest_reg_array(descr)) {
5167 /* if this fails, is_integer_guest_reg_array is
5168 returning bogus results */
5169 tl_assert(isWord);
5170 assign(
5171 'I', pce, dstv,
5172 IRExpr_GetI(
5173 mkIRRegArray(descr->base + pce->guest_state_sizeB,
5174 descr->elemTy, descr->nElems),
5175 e->Iex.GetI.ix,
5176 e->Iex.GetI.bias
5177 )
5178 );
5179 }
5180 break;
5181 }
5182
5183 case Iex_Get: {
5184 stmt( 'C', pce, st );
5185 if (isWord) {
5186 /* guest-word-typed tmp assignment, so it will have a
5187 shadow tmp, and we must make an assignment to
5188 that */
5189 if (is_integer_guest_reg(e->Iex.Get.offset,
5190 sizeofIRType(e->Iex.Get.ty))) {
5191 assign( 'I', pce, dstv,
5192 IRExpr_Get( e->Iex.Get.offset
5193 + pce->guest_state_sizeB,
5194 e->Iex.Get.ty) );
5195 } else {
5196 if (pce->hWordTy == Ity_I32) {
5197 assign( 'I', pce, dstv, mkU32( (UWord)NONPTR ));
5198 } else {
5199 assign( 'I', pce, dstv, mkU64( (UWord)NONPTR ));
5200 }
5201 }
5202 } else {
5203 /* tmp isn't guest-word-typed, so isn't shadowed, so
5204 generate no instrumentation */
5205 }
5206 break;
5207 }
5208
5209 case Iex_Unop: {
5210 stmt( 'C', pce, st );
5211 tl_assert(isIRAtom(e->Iex.Unop.arg));
5212 if (isWord)
5213 instrument_arithop( pce, dst, dstv, e->Iex.Unop.op,
5214 e->Iex.Unop.arg,
5215 NULL, NULL, NULL );
5216 break;
5217 }
5218
5219 case Iex_Binop: {
5220 stmt( 'C', pce, st );
5221 tl_assert(isIRAtom(e->Iex.Binop.arg1));
5222 tl_assert(isIRAtom(e->Iex.Binop.arg2));
5223 if (isWord)
5224 instrument_arithop( pce, dst, dstv, e->Iex.Binop.op,
5225 e->Iex.Binop.arg1, e->Iex.Binop.arg2,
5226 NULL, NULL );
5227 break;
5228 }
5229
5230 case Iex_Triop: {
5231 stmt( 'C', pce, st );
5232 tl_assert(isIRAtom(e->Iex.Triop.arg1));
5233 tl_assert(isIRAtom(e->Iex.Triop.arg2));
5234 tl_assert(isIRAtom(e->Iex.Triop.arg3));
5235 if (isWord)
5236 instrument_arithop( pce, dst, dstv, e->Iex.Triop.op,
5237 e->Iex.Triop.arg1, e->Iex.Triop.arg2,
5238 e->Iex.Triop.arg3, NULL );
5239 break;
5240 }
5241
5242 case Iex_Qop: {
5243 stmt( 'C', pce, st );
5244 tl_assert(isIRAtom(e->Iex.Qop.arg1));
5245 tl_assert(isIRAtom(e->Iex.Qop.arg2));
5246 tl_assert(isIRAtom(e->Iex.Qop.arg3));
5247 tl_assert(isIRAtom(e->Iex.Qop.arg4));
5248 if (isWord)
5249 instrument_arithop( pce, dst, dstv, e->Iex.Qop.op,
5250 e->Iex.Qop.arg1, e->Iex.Qop.arg2,
5251 e->Iex.Qop.arg3, e->Iex.Qop.arg4 );
5252 break;
5253 }
5254
5255 default:
5256 goto unhandled;
5257 } /* switch (e->tag) */
5258
5259 break;
5260
5261 } /* case Ist_WrTmp */
5262
5263 default:
5264 unhandled:
5265 ppIRStmt(st);
5266 tl_assert(0);
5267 }
5268}
5269
5270
sewardje6451332009-07-09 10:45:11 +00005271static IRTemp for_sg__newIRTemp_cb ( IRType ty, void* opaque )
5272{
5273 PCEnv* pce = (PCEnv*)opaque;
5274 return newTemp( pce, ty, NonShad );
5275}
5276
5277
sewardj024598e2008-09-18 14:43:05 +00005278IRSB* h_instrument ( VgCallbackClosure* closure,
5279 IRSB* sbIn,
5280 VexGuestLayout* layout,
5281 VexGuestExtents* vge,
5282 IRType gWordTy, IRType hWordTy )
5283{
5284 Bool verboze = 0||False;
5285 Int i /*, j*/;
5286 PCEnv pce;
5287 struct _SGEnv* sgenv;
5288
5289 if (gWordTy != hWordTy) {
5290 /* We don't currently support this case. */
5291 VG_(tool_panic)("host/guest word size mismatch");
5292 }
5293
5294 /* Check we're not completely nuts */
5295 tl_assert(sizeof(UWord) == sizeof(void*));
5296 tl_assert(sizeof(Word) == sizeof(void*));
5297 tl_assert(sizeof(Addr) == sizeof(void*));
5298 tl_assert(sizeof(ULong) == 8);
5299 tl_assert(sizeof(Long) == 8);
5300 tl_assert(sizeof(Addr64) == 8);
5301 tl_assert(sizeof(UInt) == 4);
5302 tl_assert(sizeof(Int) == 4);
5303
sewardje6451332009-07-09 10:45:11 +00005304 /* Set up the running environment. Both .sb and .tmpMap are
5305 modified as we go along. Note that tmps are added to both
5306 .sb->tyenv and .tmpMap together, so the valid index-set for
5307 those two arrays should always be identical. */
5308 VG_(memset)(&pce, 0, sizeof(pce));
5309 pce.sb = deepCopyIRSBExceptStmts(sbIn);
sewardj024598e2008-09-18 14:43:05 +00005310 pce.trace = verboze;
sewardj024598e2008-09-18 14:43:05 +00005311 pce.hWordTy = hWordTy;
5312 pce.gWordTy = gWordTy;
5313 pce.guest_state_sizeB = layout->total_sizeB;
sewardj024598e2008-09-18 14:43:05 +00005314
sewardje6451332009-07-09 10:45:11 +00005315 pce.qmpMap = VG_(newXA)( VG_(malloc), "pc.h_instrument.1", VG_(free),
5316 sizeof(TempMapEnt));
5317 for (i = 0; i < sbIn->tyenv->types_used; i++) {
5318 TempMapEnt ent;
5319 ent.kind = NonShad;
5320 ent.shadow = IRTemp_INVALID;
5321 VG_(addToXA)( pce.qmpMap, &ent );
5322 }
5323 tl_assert( VG_(sizeXA)( pce.qmpMap ) == sbIn->tyenv->types_used );
5324
5325 /* Also set up for the sg_ instrumenter. See comments at the top
5326 of this instrumentation section for details. The two parameters
5327 constitute a closure, which sg_ can use to correctly generate
5328 new IRTemps as needed. */
5329 sgenv = sg_instrument_init( for_sg__newIRTemp_cb,
5330 (void*)&pce );
sewardj024598e2008-09-18 14:43:05 +00005331
5332 /* Stay sane. These two should agree! */
sewardj4cb6bf72010-01-01 18:31:41 +00005333 tl_assert(layout->total_sizeB == PC_SIZEOF_GUEST_STATE);
sewardj024598e2008-09-18 14:43:05 +00005334
5335 /* Copy verbatim any IR preamble preceding the first IMark */
5336
5337 i = 0;
5338 while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
5339 IRStmt* st = sbIn->stmts[i];
5340 tl_assert(st);
5341 tl_assert(isFlatIRStmt(st));
5342 stmt( 'C', &pce, sbIn->stmts[i] );
5343 i++;
5344 }
5345
5346 /* Nasty problem. IR optimisation of the pre-instrumented IR may
5347 cause the IR following the preamble to contain references to IR
5348 temporaries defined in the preamble. Because the preamble isn't
5349 instrumented, these temporaries don't have any shadows.
5350 Nevertheless uses of them following the preamble will cause
5351 memcheck to generate references to their shadows. End effect is
5352 to cause IR sanity check failures, due to references to
5353 non-existent shadows. This is only evident for the complex
5354 preambles used for function wrapping on TOC-afflicted platforms
5355 (ppc64-linux, ppc32-aix5, ppc64-aix5).
5356
5357 The following loop therefore scans the preamble looking for
5358 assignments to temporaries. For each one found it creates an
5359 assignment to the corresponding shadow temp, marking it as
5360 'defined'. This is the same resulting IR as if the main
5361 instrumentation loop before had been applied to the statement
5362 'tmp = CONSTANT'.
5363 */
5364#if 0
5365 // FIXME: this isn't exactly right; only needs to generate shadows
5366 // for guest-word-typed temps
5367 for (j = 0; j < i; j++) {
5368 if (sbIn->stmts[j]->tag == Ist_WrTmp) {
5369 /* findShadowTmpV checks its arg is an original tmp;
5370 no need to assert that here. */
5371 IRTemp tmp_o = sbIn->stmts[j]->Ist.WrTmp.tmp;
5372 IRTemp tmp_s = findShadowTmp(&pce, tmp_o);
5373 IRType ty_s = typeOfIRTemp(sbIn->tyenv, tmp_s);
5374 assign( 'V', &pce, tmp_s, definedOfType( ty_s ) );
5375 if (0) {
5376 VG_(printf)("create shadow tmp for preamble tmp [%d] ty ", j);
5377 ppIRType( ty_s );
5378 VG_(printf)("\n");
5379 }
5380 }
5381 }
5382#endif
5383
5384 /* Iterate over the remaining stmts to generate instrumentation. */
5385
5386 tl_assert(sbIn->stmts_used > 0);
5387 tl_assert(i >= 0);
5388 tl_assert(i < sbIn->stmts_used);
5389 tl_assert(sbIn->stmts[i]->tag == Ist_IMark);
5390
5391 for (/*use current i*/; i < sbIn->stmts_used; i++) {
5392 /* generate sg_ instrumentation for this stmt */
sewardje6451332009-07-09 10:45:11 +00005393 sg_instrument_IRStmt( sgenv, pce.sb, sbIn->stmts[i],
sewardj024598e2008-09-18 14:43:05 +00005394 layout, gWordTy, hWordTy );
5395 /* generate h_ instrumentation for this stmt */
5396 schemeS( &pce, sbIn->stmts[i] );
5397 }
5398
5399 /* generate sg_ instrumentation for the final jump */
sewardje6451332009-07-09 10:45:11 +00005400 sg_instrument_final_jump( sgenv, pce.sb, sbIn->next, sbIn->jumpkind,
sewardj024598e2008-09-18 14:43:05 +00005401 layout, gWordTy, hWordTy );
5402
5403 /* and finalise .. */
5404 sg_instrument_fini( sgenv );
5405
sewardje6451332009-07-09 10:45:11 +00005406 /* If this fails, there's been some serious snafu with tmp management,
5407 that should be investigated. */
5408 tl_assert( VG_(sizeXA)( pce.qmpMap ) == pce.sb->tyenv->types_used );
5409 VG_(deleteXA)( pce.qmpMap );
5410
5411 return pce.sb;
sewardj024598e2008-09-18 14:43:05 +00005412}
5413
5414
5415/*--------------------------------------------------------------------*/
5416/*--- Initialisation ---*/
5417/*--------------------------------------------------------------------*/
5418
5419void h_pre_clo_init ( void )
5420{
5421 // Other initialisation
5422 init_shadow_memory();
5423 init_lossage();
5424}
5425
5426void h_post_clo_init ( void )
5427{
5428}
5429
5430/*--------------------------------------------------------------------*/
5431/*--- Finalisation ---*/
5432/*--------------------------------------------------------------------*/
5433
5434void h_fini ( Int exitcode )
5435{
sewardj2d9e8742009-08-07 15:46:56 +00005436 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5437 VG_(message)(Vg_UserMsg,
5438 "For counts of detected and suppressed errors, "
5439 "rerun with: -v\n");
5440 }
5441
5442 if (VG_(clo_stats)) {
sewardj024598e2008-09-18 14:43:05 +00005443 VG_(message)(Vg_DebugMsg,
sewardjc1bc9d12009-07-15 14:50:22 +00005444 " h_: %'10llu client allocs, %'10llu client frees\n",
sewardj024598e2008-09-18 14:43:05 +00005445 stats__client_mallocs, stats__client_frees);
5446 VG_(message)(Vg_DebugMsg,
sewardjc1bc9d12009-07-15 14:50:22 +00005447 " h_: %'10llu Segs allocd, %'10llu Segs recycled\n",
sewardj024598e2008-09-18 14:43:05 +00005448 stats__segs_allocd, stats__segs_recycled);
sewardj024598e2008-09-18 14:43:05 +00005449 }
5450
sewardj4815eb52008-10-20 23:33:49 +00005451#if 0
sewardj024598e2008-09-18 14:43:05 +00005452 if (h_clo_lossage_check) {
sewardjc1bc9d12009-07-15 14:50:22 +00005453 VG_(message)(Vg_UserMsg, "\n");
5454 VG_(message)(Vg_UserMsg, "%12lld total memory references\n",
sewardj024598e2008-09-18 14:43:05 +00005455 stats__tot_mem_refs);
sewardjc1bc9d12009-07-15 14:50:22 +00005456 VG_(message)(Vg_UserMsg, "%12lld of which are in a known segment\n",
sewardj024598e2008-09-18 14:43:05 +00005457 stats__refs_in_a_seg);
sewardjc1bc9d12009-07-15 14:50:22 +00005458 VG_(message)(Vg_UserMsg, "%12lld of which are 'lost' w.r.t the seg\n",
sewardj024598e2008-09-18 14:43:05 +00005459 stats__refs_lost_seg);
sewardjc1bc9d12009-07-15 14:50:22 +00005460 VG_(message)(Vg_UserMsg, "\n");
sewardj024598e2008-09-18 14:43:05 +00005461 show_lossage();
sewardjc1bc9d12009-07-15 14:50:22 +00005462 VG_(message)(Vg_UserMsg, "\n");
sewardj024598e2008-09-18 14:43:05 +00005463 } else {
5464 tl_assert( 0 == VG_(OSetGen_Size)(lossage) );
5465 }
sewardj4815eb52008-10-20 23:33:49 +00005466#endif
sewardj024598e2008-09-18 14:43:05 +00005467}
5468
5469
5470/*--------------------------------------------------------------------*/
5471/*--- end h_main.c ---*/
5472/*--------------------------------------------------------------------*/