From ae2f76fb789651882355dc0d57c39c6d69cc8edf Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 29 Oct 2013 19:44:47 +0000 Subject: [PATCH] [msandr] Add support for standalone test. Add macro MSANDR_STANDALONE_TEST for standalone test without msan executables. Patch by Qin Zhao. llvm-svn: 193643 --- compiler-rt/lib/msandr/CMakeLists.txt | 5 -- compiler-rt/lib/msandr/msandr.cc | 133 ++++++++++++++++++++++++++++++++-- 2 files changed, 128 insertions(+), 10 deletions(-) diff --git a/compiler-rt/lib/msandr/CMakeLists.txt b/compiler-rt/lib/msandr/CMakeLists.txt index e302726..5a96a9d 100644 --- a/compiler-rt/lib/msandr/CMakeLists.txt +++ b/compiler-rt/lib/msandr/CMakeLists.txt @@ -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}) diff --git a/compiler-rt/lib/msandr/msandr.cc b/compiler-rt/lib/msandr/msandr.cc index 7aef0c4..ffea3e8 100644 --- a/compiler-rt/lib/msandr/msandr.cc +++ b/compiler-rt/lib/msandr/msandr.cc @@ -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 -- 2.7.4