mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-08 08:26:14 +00:00
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 "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;
|
|
}
|