1
2/* Test Valgrind's ability to spot writes to code which has been
3   translated, and discard the out-of-date translations.
4
5   CORRECT output is
6
7      in p 0
8      in q 1
9      in p 2
10      in q 3
11      in p 4
12      in q 5
13      in p 6
14      in q 7
15      in p 8
16      in q 9
17
18  WRONG output (if you fail to spot code-writes to code[0 .. 4]) is
19
20      in p 0
21      in p 1
22      in p 2
23      in p 3
24      in p 4
25      in p 5
26      in p 6
27      in p 7
28      in p 8
29      in p 9
30*/
31
32#include <stdio.h>
33#include <assert.h>
34#include "tests/sys_mman.h"
35
36typedef unsigned long long int Addr;
37typedef unsigned char UChar;
38
39void q ( int n )
40{
41   printf("in q %d\n", n);
42}
43
44void p ( int n )
45{
46   printf("in p %d\n", n);
47}
48
49// Unlike on x86, data areas aren't executable; have to put
50// code on the heap therefore
51static UChar* code;
52
53/* Make `code' be  movabsq $dest, %rax ; pushq %rax ; ret */
54// This forces the branch onwards to be indirect, so vex can't chase it
55void set_dest ( Addr dest )
56{
57   assert(sizeof(Addr) == 8);
58
59   /* movabsq $imm64, %rax */
60   code[0] = 0x48;
61   code[1] = 0xB8;
62   code[2] = (dest & 0xFF);
63   code[3] = ((dest >>  8) & 0xFF);
64   code[4] = ((dest >> 16) & 0xFF);
65   code[5] = ((dest >> 24) & 0xFF);
66   code[6] = ((dest >> 32) & 0xFF);
67   code[7] = ((dest >> 40) & 0xFF);
68   code[8] = ((dest >> 48) & 0xFF);
69   code[9] = ((dest >> 56) & 0xFF);
70
71   /* pushq %rax */
72   code[10] = 0x50;
73
74   /* ret */
75   code[11] = 0xC3;
76}
77
78/* Calling aa gets eventually to the function residing in code[0..].
79   This indirection is necessary to defeat Vex's basic-block chasing
80   optimisation.  That will merge up to three basic blocks into the
81   same IR superblock, which causes the test to succeed when it
82   shouldn't if main calls code[] directly.  */
83
84// force an indirect branch to code[0], so vex can't chase it
85__attribute__((noinline))
86void dd ( int x, void (*f)(int) ) { f(x); }
87
88__attribute__((noinline))
89void cc ( int x ) { dd(x, (void(*)(int)) &code[0]); }
90
91__attribute__((noinline))
92void bb ( int x ) { cc(x); }
93
94__attribute__((noinline))
95void aa ( int x ) { bb(x); }
96
97__attribute__((noinline))
98void diversion ( void ) { }
99
100int main ( void )
101{
102   int i;
103   code = mmap(NULL, 20, PROT_READ|PROT_WRITE|PROT_EXEC,
104               MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
105   assert(code != MAP_FAILED);
106   for (i = 0; i < 10; i += 2) {
107      set_dest ( (Addr)&p );
108      //      diversion();
109      aa(i);
110      set_dest ( (Addr)&q );
111      //      diversion();
112      aa(i+1);
113   }
114   munmap(code, 20);
115   return 0;
116}
117