File: smc1.c

package info (click to toggle)
valgrind 1%3A3.12.0~svn20160714-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 120,428 kB
  • ctags: 70,855
  • sloc: ansic: 674,645; exp: 26,134; xml: 21,574; asm: 7,570; cpp: 7,567; makefile: 7,380; sh: 6,188; perl: 5,855; haskell: 195
file content (116 lines) | stat: -rw-r--r-- 2,526 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

/* Test Valgrind's ability to spot writes to code which has been
   translated, and discard the out-of-date translations.

   CORRECT output is

      in p 0
      in q 1
      in p 2
      in q 3
      in p 4
      in q 5
      in p 6
      in q 7
      in p 8
      in q 9

  WRONG output (if you fail to spot code-writes to code[0 .. 4]) is

      in p 0
      in p 1
      in p 2
      in p 3
      in p 4
      in p 5
      in p 6
      in p 7
      in p 8
      in p 9
*/

#include <stdio.h>
#include <assert.h>
#include "tests/sys_mman.h"

typedef unsigned long long int Addr;
typedef unsigned char UChar;

void q ( int n )
{
   printf("in q %d\n", n);
}

void p ( int n )
{
   printf("in p %d\n", n);
}

// Unlike on x86, data areas aren't executable; have to put
// code on the heap therefore
static UChar* code;

/* Make `code' be  movabsq $dest, %rax ; pushq %rax ; ret */
// This forces the branch onwards to be indirect, so vex can't chase it
void set_dest ( Addr dest )
{
   assert(sizeof(Addr) == 8);

   /* movabsq $imm64, %rax */
   code[0] = 0x48;
   code[1] = 0xB8;
   code[2] = (dest & 0xFF);
   code[3] = ((dest >>  8) & 0xFF);
   code[4] = ((dest >> 16) & 0xFF);
   code[5] = ((dest >> 24) & 0xFF);
   code[6] = ((dest >> 32) & 0xFF);
   code[7] = ((dest >> 40) & 0xFF);
   code[8] = ((dest >> 48) & 0xFF);
   code[9] = ((dest >> 56) & 0xFF);

   /* pushq %rax */
   code[10] = 0x50;

   /* ret */
   code[11] = 0xC3;
}

/* Calling aa gets eventually to the function residing in code[0..].
   This indirection is necessary to defeat Vex's basic-block chasing
   optimisation.  That will merge up to three basic blocks into the
   same IR superblock, which causes the test to succeed when it
   shouldn't if main calls code[] directly.  */

// force an indirect branch to code[0], so vex can't chase it
__attribute__((noinline))
void dd ( int x, void (*f)(int) ) { f(x); }

__attribute__((noinline))
void cc ( int x ) { dd(x, (void(*)(int)) &code[0]); }

__attribute__((noinline))
void bb ( int x ) { cc(x); }

__attribute__((noinline))
void aa ( int x ) { bb(x); }

__attribute__((noinline))
void diversion ( void ) { }

int main ( void )
{
   int i;
   code = mmap(NULL, 20, PROT_READ|PROT_WRITE|PROT_EXEC,
               MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
   assert(code != MAP_FAILED);
   for (i = 0; i < 10; i += 2) {
      set_dest ( (Addr)&p );
      //      diversion();
      aa(i);
      set_dest ( (Addr)&q );
      //      diversion();
      aa(i+1);
   }
   munmap(code, 20);
   return 0;
}