Index: include/sanitizer/common_interface_defs.h =================================================================== --- include/sanitizer/common_interface_defs.h +++ include/sanitizer/common_interface_defs.h @@ -182,6 +182,13 @@ void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old); + + // Get full module name and calculate pc offset within it. + // Returns 1 if pc belongs to some module, 0 if module was not found. + int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path, + size_t module_path_len, + void **pc_offset); + #ifdef __cplusplus } // extern "C" #endif Index: lib/asan/asan_win_dll_thunk.cc =================================================================== --- lib/asan/asan_win_dll_thunk.cc +++ lib/asan/asan_win_dll_thunk.cc @@ -366,6 +366,7 @@ INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks) INTERFACE_FUNCTION(__sanitizer_start_switch_fiber) INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber) +INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc) // TODO(timurrrr): Add more interface functions on the as-needed basis. Index: lib/sanitizer_common/sanitizer_common_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_common_libcdep.cc +++ lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -160,6 +160,18 @@ #endif } +static int GetModuleAndOffsetForPc(uptr pc, char *module_name, + uptr module_name_len, uptr *pc_offset) { + const char *found_module_name = nullptr; + bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC( + pc, &found_module_name, pc_offset); + + if (!ok) return false; + + internal_strncpy(module_name, found_module_name, module_name_len); + return true; +} + } // namespace __sanitizer void NOINLINE @@ -168,3 +180,13 @@ if (__sanitizer::sandboxing_callback) __sanitizer::sandboxing_callback(); } + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE int +__sanitizer_get_module_and_offset_for_pc(void *pc, // NOLINT + char *module_name, + uptr module_name_len, + void **pc_offset) { + return __sanitizer::GetModuleAndOffsetForPc( + reinterpret_cast(pc), module_name, module_name_len, + reinterpret_cast(pc_offset)); +} Index: lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -55,7 +55,7 @@ // own demangler (libc++abi's implementation could be adapted so that // it does not allocate). For now, we just call it anyway, and we leak // the returned value. - if (__cxxabiv1::__cxa_demangle) + if (&__cxxabiv1::__cxa_demangle) if (const char *demangled_name = __cxxabiv1::__cxa_demangle(name, 0, 0, 0)) return demangled_name; Index: lib/tsan/CMakeLists.txt =================================================================== --- lib/tsan/CMakeLists.txt +++ lib/tsan/CMakeLists.txt @@ -128,6 +128,7 @@ set(BUILDGO_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/go/buildgo.sh) add_custom_target(GotsanRuntimeCheck COMMAND env "CC=${CMAKE_C_COMPILER} ${OSX_SYSROOT_FLAG}" + "CXX=${CMAKE_CXX_COMPILER} ${OSX_SYSROOT_FLAG}" IN_TMPDIR=1 SILENT=1 ${BUILDGO_SCRIPT} DEPENDS tsan ${BUILDGO_SCRIPT} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go @@ -144,6 +145,7 @@ set(BUILDGO_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/go/buildgo.sh) add_custom_target(GotsanRuntimeCheck COMMAND env "CC=${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" + "CXX=${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" IN_TMPDIR=1 SILENT=1 ${BUILDGO_SCRIPT} DEPENDS clang_rt.tsan-${arch} ${BUILDGO_SCRIPT} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go Index: lib/tsan/go/buildgo.sh =================================================================== --- lib/tsan/go/buildgo.sh +++ lib/tsan/go/buildgo.sh @@ -33,13 +33,15 @@ ../../sanitizer_common/sanitizer_stackdepot.cc ../../sanitizer_common/sanitizer_stacktrace.cc ../../sanitizer_common/sanitizer_symbolizer.cc + ../../sanitizer_common/sanitizer_symbolizer_libcdep.cc + ../../sanitizer_common/sanitizer_symbolizer_libbacktrace.cc ../../sanitizer_common/sanitizer_termination.cc " if [ "`uname -a | grep Linux`" != "" ]; then SUFFIX="linux_amd64" OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Wno-unused-const-variable -Werror -Wno-unknown-warning-option" - OSLDFLAGS="-lpthread -fPIC -fpie" + OSLDFLAGS="-lpthread -ldl -fPIC -fpie" SRCS=" $SRCS ../rtl/tsan_platform_linux.cc @@ -50,11 +52,12 @@ ../../sanitizer_common/sanitizer_linux.cc ../../sanitizer_common/sanitizer_linux_libcdep.cc ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc + ../../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc " elif [ "`uname -a | grep FreeBSD`" != "" ]; then SUFFIX="freebsd_amd64" OSCFLAGS="-fno-strict-aliasing -fPIC -Werror" - OSLDFLAGS="-lpthread -fPIC -fpie" + OSLDFLAGS="-lpthread -ldl -fPIC -fpie" SRCS=" $SRCS ../rtl/tsan_platform_linux.cc @@ -65,11 +68,12 @@ ../../sanitizer_common/sanitizer_linux.cc ../../sanitizer_common/sanitizer_linux_libcdep.cc ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc + ../../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc " elif [ "`uname -a | grep Darwin`" != "" ]; then SUFFIX="darwin_amd64" OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option -mmacosx-version-min=10.7" - OSLDFLAGS="-lpthread -fPIC -fpie -mmacosx-version-min=10.7" + OSLDFLAGS="-lpthread -ldl -fPIC -fpie -mmacosx-version-min=10.7" SRCS=" $SRCS ../rtl/tsan_platform_mac.cc @@ -77,6 +81,7 @@ ../../sanitizer_common/sanitizer_posix.cc ../../sanitizer_common/sanitizer_posix_libcdep.cc ../../sanitizer_common/sanitizer_procmaps_mac.cc + ../../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc " elif [ "`uname -a | grep MINGW`" != "" ]; then SUFFIX="windows_amd64" @@ -86,6 +91,7 @@ $SRCS ../rtl/tsan_platform_windows.cc ../../sanitizer_common/sanitizer_win.cc + ../../sanitizer_common/sanitizer_symbolizer_win.cc " else echo Unknown platform @@ -93,6 +99,7 @@ fi CC=${CC:-gcc} +CXX=${CXX:-g++} IN_TMPDIR=${IN_TMPDIR:-0} SILENT=${SILENT:-0} @@ -121,11 +128,12 @@ fi if [ "$SILENT" != "1" ]; then - echo $CC gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS + echo $CXX gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS fi -$CC $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS +$CXX $DIR/gotsan.cc -c -o $DIR/race_$SUFFIX.syso $FLAGS $CFLAGS -$CC $OSCFLAGS test.c $DIR/race_$SUFFIX.syso -m64 -g -o $DIR/test $OSLDFLAGS +$CC $OSCFLAGS test.c -m64 -g -c -o $DIR/test.o +$CXX $OSCFLAGS $DIR/test.o $DIR/race_$SUFFIX.syso -m64 -g -o $DIR/test $OSLDFLAGS export GORACE="exitcode=0 atexit_sleep_ms=0" if [ "$SILENT" != "1" ]; then Index: test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc @@ -0,0 +1,63 @@ +// RUN: %clangxx -DSHARED %s -shared -o %T/get_module_and_offset_for_pc.so -fPIC +// RUN: %clangxx -DSO_DIR=\"%T\" -O0 %s -ldl -o %t +// RUN: %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: i386-darwin +// +// Tests __sanitizer_get_module_and_offset_for_pc. + +#include +#include +#include +#include + +#ifdef SHARED +extern "C" { +int foo() { return 1; } +} +#else + +void Test(void *pc, const char *name) { + char module_name[1024]; + void *offset; + int ok = __sanitizer_get_module_and_offset_for_pc( + pc, module_name, sizeof(module_name), &offset); + if (!ok) { + printf("NOT FOUND %s: %p\n", name, pc); + } else { + printf("FOUND %s: %s %p\n", name, module_name, offset); + } +} + +void TestCallerPc() { Test(__builtin_return_address(0), "callerpc"); } + +void TestDlsym() { + void *handle = dlopen(SO_DIR "/get_module_and_offset_for_pc.so", RTLD_LAZY); + assert(handle); + void *foo = dlsym(handle, "foo"); + assert(foo); + Test(foo, "foo"); + dlclose(handle); +} + +// Call __sanitizer_get_module_and_offset_for_pc lots of times +// to make sure it is not too slow. +void TestLoop() { + void *pc = __builtin_return_address(0); + char module_name[1024]; + void *offset; + for (int i = 0; i < 1000000; ++i) { + __sanitizer_get_module_and_offset_for_pc(pc, module_name, + sizeof(module_name), &offset); + } +} + +int main() { + Test(0, "null"); + TestCallerPc(); + TestDlsym(); + TestLoop(); +} +#endif +// CHECK: NOT FOUND null: (nil) +// CHECK-NEXT: FOUND callerpc: {{.*}}/get_module_and_offset_for_pc.cc.tmp {{.*}} +// CHECK-NEXT: FOUND foo: {{.*}}/get_module_and_offset_for_pc.so {{.*}}