forked from OSchip/llvm-project
[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:
parent
8c8711207c
commit
ae2f76fb78
|
@ -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})
|
||||
|
|
|
@ -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(®_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(®_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
|
||||
|
|
Loading…
Reference in New Issue