mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-11 22:08:14 +00:00
normally give execute permission to memory allocated from the heap with sbrk. This also required fixing the smc1 test for amd64 to use mmap to allocate memory so that it can have execute permission. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@4983
117 lines
2.5 KiB
C
117 lines
2.5 KiB
C
|
|
/* 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 <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;
|
|
}
|