Home | History | Annotate | Download | only in amd64
      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 
     36 typedef unsigned long long int Addr;
     37 typedef unsigned char UChar;
     38 
     39 void q ( int n )
     40 {
     41    printf("in q %d\n", n);
     42 }
     43 
     44 void 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
     51 static 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
     55 void 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))
     86 void dd ( int x, void (*f)(int) ) { f(x); }
     87 
     88 __attribute__((noinline))
     89 void cc ( int x ) { dd(x, (void(*)(int)) &code[0]); }
     90 
     91 __attribute__((noinline))
     92 void bb ( int x ) { cc(x); }
     93 
     94 __attribute__((noinline))
     95 void aa ( int x ) { bb(x); }
     96 
     97 __attribute__((noinline))
     98 void diversion ( void ) { }
     99 
    100 int 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