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
34typedef unsigned int Addr;
35typedef unsigned char UChar;
36
37void q ( int n )
38{
39   printf("in q %d\n", n);
40}
41
42void p ( int n )
43{
44   printf("in p %d\n", n);
45}
46
47static UChar code[10];
48
49/* Make `code' be PUSHL $dest ; ret */
50// This forces the branch onwards to be indirect, so vex can't chase it
51void set_dest ( Addr dest )
52{
53   code[0] = 0x68; /* PUSH imm32 */
54   code[1] = (dest & 0xFF);
55   code[2] = ((dest >> 8) & 0xFF);
56   code[3] = ((dest >> 16) & 0xFF);
57   code[4] = ((dest >> 24) & 0xFF);
58   code[5] = 0xC3;
59}
60
61/* Calling aa gets eventually to the function residing in code[0..].
62   This indirection is necessary to defeat Vex's basic-block chasing
63   optimisation.  That will merge up to three basic blocks into the
64   same IR superblock, which causes the test to succeed when it
65   shouldn't if main calls code[] directly.  */
66
67// force an indirect branch to code[0], so vex can't chase it
68__attribute__((noinline))
69void dd ( int x, void (*f)(int) ) { f(x); }
70
71__attribute__((noinline))
72void cc ( int x ) { dd(x, (void(*)(int)) &code[0]); }
73
74__attribute__((noinline))
75void bb ( int x ) { cc(x); }
76
77__attribute__((noinline))
78void aa ( int x ) { bb(x); }
79
80__attribute__((noinline))
81void diversion ( void ) { }
82
83int main ( void )
84{
85   int i;
86   for (i = 0; i < 10; i += 2) {
87      set_dest ( (Addr)&p );
88      //      diversion();
89      aa(i);
90      set_dest ( (Addr)&q );
91      //      diversion();
92      aa(i+1);
93   }
94   return 0;
95}
96