[msandr] Add support for standalone test.

Add macro MSANDR_STANDALONE_TEST for standalone test without msan executables.

Patch by Qin Zhao.

llvm-svn: 193643
This commit is contained in:
Evgeniy Stepanov 2013-10-29 19:44:47 +00:00
parent 8c8711207c
commit ae2f76fb78
2 changed files with 128 additions and 10 deletions

View File

@ -4,11 +4,6 @@ if(DynamoRIO_DIR AND DrMemoryFramework_DIR)
find_package(DynamoRIO)
find_package(DrMemoryFramework)
option(MSANDR_NATIVE_EXEC "Building msandr client for running in DynamoRIO hybrid mode, which allows some module running natively" OFF)
if (MSANDR_NATIVE_EXEC)
add_definitions(-DMSANDR_NATIVE_EXEC)
endif (MSANDR_NATIVE_EXEC)
set(arch "x86_64")
add_library(clang_rt.msandr-${arch} SHARED msandr.cc)
configure_DynamoRIO_client(clang_rt.msandr-${arch})

View File

@ -60,6 +60,35 @@
#define VERBOSITY 0
// XXX: it seems setting macro in CMakeLists.txt does not work,
// so manually set it here now.
// Building msandr client for running in DynamoRIO hybrid mode,
// which allows some module running natively.
// TODO: turn it on by default when hybrid is stable enough
// #define MSANDR_NATIVE_EXEC
// Building msandr client for standalone test that does not need to
// run with msan build executables. Disable by default.
// #define MSANDR_STANDALONE_TEST
#define NUM_TLS_RETVAL 1
#define NUM_TLS_PARAM 6
#ifdef MSANDR_STANDALONE_TEST
// For testing purpose, we map app to shadow memory at [0x100000, 0x20000).
// Normally, the app starts at 0x400000:
// 00400000-004e0000 r-xp 00000000 fc:00 524343 /bin/bash
// so there should be no problem.
# define SHADOW_MEMORY_BASE ((void *)0x100000)
# define SHADOW_MEMORY_SIZE (0x100000)
# define SHADOW_MEMORY_MASK (SHADOW_MEMORY_SIZE - 4 /* to avoid overflow */)
#else
// shadow memory range [0x200000000000, 0x400000000000)
// assuming no app memory below 0x200000000000
# define SHADOW_MEMORY_MASK 0x3fffffffffffULL
#endif /* MSANDR_STANDALONE_TEST */
namespace {
std::string g_app_path;
@ -107,13 +136,47 @@ int(*__msan_get_param_tls_offset)();
void (*__msan_unpoison)(void *base, size_t size);
bool (*__msan_is_in_loader)();
#ifdef MSANDR_STANDALONE_TEST
uint mock_msan_retval_tls_offset;
uint mock_msan_param_tls_offset;
static int mock_msan_get_retval_tls_offset() {
return (int)mock_msan_retval_tls_offset;
}
static int mock_msan_get_param_tls_offset() {
return (int)mock_msan_param_tls_offset;
}
static void mock_msan_unpoison(void *base, size_t size) {
/* do nothing */
}
static bool mock_msan_is_in_loader() {
return false;
}
#endif /* MSANDR_STANDALONE_TEST */
static generic_func_t LookupCallback(module_data_t *app, const char *name) {
#ifdef MSANDR_STANDALONE_TEST
if (strcmp("__msan_get_retval_tls_offset", name) == 0) {
return (generic_func_t)mock_msan_get_retval_tls_offset;
} else if (strcmp("__msan_get_param_tls_offset", name) == 0) {
return (generic_func_t)mock_msan_get_param_tls_offset;
} else if (strcmp("__msan_unpoison", name) == 0) {
return (generic_func_t)mock_msan_unpoison;
} else if (strcmp("__msan_is_in_loader", name) == 0) {
return (generic_func_t)mock_msan_is_in_loader;
}
CHECK(false);
return NULL;
#else /* !MSANDR_STANDALONE_TEST */
generic_func_t callback = dr_get_proc_address(app->handle, name);
if (callback == NULL) {
dr_printf("Couldn't find `%s` in %s\n", name, app->full_path);
CHECK(callback);
}
return callback;
#endif /* !MSANDR_STANDALONE_TEST */
}
void InitializeMSanCallbacks() {
@ -243,16 +306,22 @@ void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
if (!address_in_R1)
CHECK(drutil_insert_get_mem_addr(drcontext, bb, instr, op, R1, R2));
PRE(instr, mov_imm(drcontext, opnd_create_reg(R2),
OPND_CREATE_INT64(0xffffbfffffffffff)));
OPND_CREATE_INT64(SHADOW_MEMORY_MASK)));
PRE(instr, and(drcontext, opnd_create_reg(R1), opnd_create_reg(R2)));
#ifdef MSANDR_STANDALONE_TEST
PRE(instr, add(drcontext, opnd_create_reg(R1),
OPND_CREATE_INT32(SHADOW_MEMORY_BASE)));
#endif
// There is no mov_st of a 64-bit immediate, so...
opnd_size_t op_size = opnd_get_size(op);
CHECK(op_size != OPSZ_NA);
uint access_size = opnd_size_in_bytes(op_size);
if (access_size <= 4) {
// TODO: optimize it with check-before-write
if (access_size <= 4 || op_size == OPSZ_PTR /* x64 support sign extension */) {
PRE(instr,
mov_st(drcontext, opnd_create_base_disp(R1, DR_REG_NULL, 0, 0, op_size),
opnd_create_immed_int((ptr_int_t) 0, op_size)));
opnd_create_immed_int((ptr_int_t) 0,
(op_size == OPSZ_PTR) ? OPSZ_4 : op_size)));
} else {
// FIXME: tail?
for (uint ofs = 0; ofs < access_size; ofs += 4) {
@ -280,6 +349,18 @@ void InstrumentMops(void *drcontext, instrlist_t *bb, instr_t *instr, opnd_t op,
}
void InstrumentReturn(void *drcontext, instrlist_t *bb, instr_t *instr) {
#ifdef MSANDR_STANDALONE_TEST
PRE(instr,
mov_st(drcontext,
opnd_create_far_base_disp(DR_SEG_GS /* DR's TLS */,
DR_REG_NULL, DR_REG_NULL,
0, msan_retval_tls_offset,
OPSZ_PTR),
OPND_CREATE_INT32(0)));
#else /* !MSANDR_STANDALONE_TEST */
/* XXX: the code below only works if -mangle_app_seg and -private_loader,
* which is turned of for optimized native exec
*/
dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
// Clobbers nothing except xax.
@ -296,10 +377,27 @@ void InstrumentReturn(void *drcontext, instrlist_t *bb, instr_t *instr) {
// The original instruction is left untouched. The above instrumentation is just
// a prefix.
#endif /* !MSANDR_STANDALONE_TEST */
}
void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb,
instr_t *instr) {
#ifdef MSANDR_STANDALONE_TEST
for (int i = 0; i < NUM_TLS_PARAM; ++i) {
PRE(instr,
mov_st(drcontext,
opnd_create_far_base_disp(DR_SEG_GS /* DR's TLS */,
DR_REG_NULL, DR_REG_NULL,
0,
msan_param_tls_offset +
i * sizeof(void *),
OPSZ_PTR),
OPND_CREATE_INT32(0)));
}
#else /* !MSANDR_STANDALONE_TEST */
/* XXX: the code below only works if -mangle_app_seg and -private_loader,
* which is turned off for optimized native exec
*/
dr_save_reg(drcontext, bb, instr, DR_REG_XAX, SPILL_SLOT_1);
// Clobbers nothing except xax.
@ -308,7 +406,7 @@ void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb,
CHECK(res);
// TODO: unpoison more bytes?
for (int i = 0; i < 6; ++i) {
for (int i = 0; i < NUM_TLS_PARAM; ++i) {
PRE(instr,
mov_st(drcontext, OPND_CREATE_MEMPTR(DR_REG_XAX, msan_param_tls_offset +
i * sizeof(void *)),
@ -319,6 +417,7 @@ void InstrumentIndirectBranch(void *drcontext, instrlist_t *bb,
// The original instruction is left untouched. The above instrumentation is just
// a prefix.
#endif /* !MSANDR_STANDALONE_TEST */
}
#ifndef MSANDR_NATIVE_EXEC
@ -376,7 +475,7 @@ bool ShouldInstrumentPc(app_pc pc, ModuleData **pmod_data) {
}
return true;
}
#endif /* !NATIVE_CLIENT */
#endif /* !MSANDR_NATIVE_CLIENT */
// TODO(rnk): Make sure we instrument after __msan_init.
dr_emit_flags_t
@ -525,6 +624,15 @@ void event_exit() {
drutil_exit();
drmgr_exit();
#ifdef MSANDR_STANDALONE_TEST
/* free tls */
bool res;
res = dr_raw_tls_cfree(msan_retval_tls_offset, NUM_TLS_RETVAL);
CHECK(res);
res = dr_raw_tls_cfree(msan_param_tls_offset, NUM_TLS_PARAM);
CHECK(res);
/* we do not bother to free the shadow memory */
#endif /* !MSANDR_STANDALONE_TEST */
if (VERBOSITY > 0)
dr_printf("==DRMSAN== DONE\n");
}
@ -701,6 +809,21 @@ DR_EXPORT void dr_init(client_id_t id) {
res = drsys_filter_all_syscalls();
CHECK(res == DRMF_SUCCESS);
#ifdef MSANDR_STANDALONE_TEST
reg_id_t reg_seg;
/* alloc tls */
if (!dr_raw_tls_calloc(&reg_seg, &mock_msan_retval_tls_offset, NUM_TLS_RETVAL, 0))
CHECK(false);
CHECK(reg_seg == DR_SEG_GS /* x64 only! */);
if (!dr_raw_tls_calloc(&reg_seg, &mock_msan_param_tls_offset, NUM_TLS_PARAM, 0))
CHECK(false);
CHECK(reg_seg == DR_SEG_GS /* x64 only! */);
/* alloc shadow memory */
if (mmap(SHADOW_MEMORY_BASE, SHADOW_MEMORY_SIZE, PROT_READ|PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0) != SHADOW_MEMORY_BASE) {
CHECK(false);
}
#endif /* MSANDR_STANDALONE_TEST */
InitializeMSanCallbacks();
// FIXME: the shadow is initialized earlier when DR calls one of our wrapper