summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2013-10-29 19:44:47 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2013-10-29 19:44:47 +0000
commit4b26afda2f4c7465260b22f1094c6699886cc55d (patch)
tree8aafd06f461e62e511c5ef54dd46e8fe26337596
parent0b76578bf5bf04a0674ac5a27ade01e3da26a0c9 (diff)
downloadcompiler-rt-4b26afda2f4c7465260b22f1094c6699886cc55d.tar.gz
compiler-rt-4b26afda2f4c7465260b22f1094c6699886cc55d.tar.bz2
compiler-rt-4b26afda2f4c7465260b22f1094c6699886cc55d.tar.xz
[msandr] Add support for standalone test.
Add macro MSANDR_STANDALONE_TEST for standalone test without msan executables. Patch by Qin Zhao. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@193643 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/msandr/CMakeLists.txt5
-rw-r--r--lib/msandr/msandr.cc133
2 files changed, 128 insertions, 10 deletions
diff --git a/lib/msandr/CMakeLists.txt b/lib/msandr/CMakeLists.txt
index e302726b..5a96a9dc 100644
--- a/lib/msandr/CMakeLists.txt
+++ b/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/lib/msandr/msandr.cc b/lib/msandr/msandr.cc
index 7aef0c4f..ffea3e8a 100644
--- a/lib/msandr/msandr.cc
+++ b/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(&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