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 34 typedef unsigned int Addr; 35 typedef unsigned char UChar; 36 37 void q ( int n ) 38 { 39 printf("in q %d\n", n); 40 } 41 42 void p ( int n ) 43 { 44 printf("in p %d\n", n); 45 } 46 47 static 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 51 void 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)) 69 void dd ( int x, void (*f)(int) ) { f(x); } 70 71 __attribute__((noinline)) 72 void cc ( int x ) { dd(x, (void(*)(int)) &code[0]); } 73 74 __attribute__((noinline)) 75 void bb ( int x ) { cc(x); } 76 77 __attribute__((noinline)) 78 void aa ( int x ) { bb(x); } 79 80 __attribute__((noinline)) 81 void diversion ( void ) { } 82 83 int 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