diff options
author | Derek Bruening <bruening@google.com> | 2016-04-21 21:32:25 +0000 |
---|---|---|
committer | Derek Bruening <bruening@google.com> | 2016-04-21 21:32:25 +0000 |
commit | 33f89a1f101182f2f316a3e142caa93d244b4ee7 (patch) | |
tree | e612c4052a65867414acb78ae588d500b20d7484 /lib | |
parent | 94a44ec2b58ed284cb7175b7ed605ae8675a7de9 (diff) |
[esan] EfficiencySanitizer base runtime library
Summary:
Adds the initial version of a runtime library for the new
EfficiencySanitizer ("esan") family of tools. The library includes:
+ Slowpath code via callouts from the compiler instrumentation for
each memory access.
+ Registration of atexit() to call finalization code.
+ Runtime option flags controlled by the environment variable
ESAN_OPTIONS. The common sanitizer flags are supported such as
verbosity and log_path.
+ An initial simple test.
Still TODO: common code for libc interceptors and shadow memory mapping,
and tool-specific code for shadow state updating.
Reviewers: eugenis, vitalybuka, aizatsky, filcab
Subscribers: filcab, vkalintiris, kubabrecka, llvm-commits, zhaoqin, kcc
Differential Revision: http://reviews.llvm.org/D19168
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@267060 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/esan/CMakeLists.txt | 35 | ||||
-rw-r--r-- | lib/esan/esan.cpp | 112 | ||||
-rw-r--r-- | lib/esan/esan.h | 44 | ||||
-rw-r--r-- | lib/esan/esan.syms.extra | 3 | ||||
-rw-r--r-- | lib/esan/esan_interface.cpp | 102 | ||||
-rw-r--r-- | lib/esan/esan_interface_internal.h | 72 |
7 files changed, 372 insertions, 0 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 718b12820..7a8210e42 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -48,4 +48,8 @@ if(COMPILER_RT_BUILD_SANITIZERS) if(COMPILER_RT_HAS_CFI) add_subdirectory(cfi) endif() + + if(COMPILER_RT_HAS_ESAN) + add_subdirectory(esan) + endif() endif() diff --git a/lib/esan/CMakeLists.txt b/lib/esan/CMakeLists.txt new file mode 100644 index 000000000..be4994f1d --- /dev/null +++ b/lib/esan/CMakeLists.txt @@ -0,0 +1,35 @@ +# Build for the EfficiencySanitizer runtime support library. + +add_custom_target(esan) + +set(ESAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS}) +append_rtti_flag(OFF ESAN_RTL_CFLAGS) + +include_directories(..) + +set(ESAN_SOURCES + esan.cpp + esan_interface.cpp) + +foreach (arch ${ESAN_SUPPORTED_ARCH}) + add_compiler_rt_runtime(clang_rt.esan + STATIC + ARCHS ${arch} + SOURCES ${ESAN_SOURCES} + $<TARGET_OBJECTS:RTInterception.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + CFLAGS ${ESAN_RTL_CFLAGS}) + add_sanitizer_rt_symbols(clang_rt.esan + ARCHS ${arch} + EXTRA esan.syms.extra) + add_dependencies(esan + clang_rt.esan-${arch} + clang_rt.esan-${arch}-symbols) +endforeach() + +add_dependencies(compiler-rt esan) + +if (COMPILER_RT_INCLUDE_TESTS) + # TODO(bruening): add tests via add_subdirectory(tests) +endif() diff --git a/lib/esan/esan.cpp b/lib/esan/esan.cpp new file mode 100644 index 000000000..566d13995 --- /dev/null +++ b/lib/esan/esan.cpp @@ -0,0 +1,112 @@ +//===-- esan.cpp ----------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Main file (entry points) for the Esan run-time. +//===----------------------------------------------------------------------===// + +#include "esan.h" +#include "esan_interface_internal.h" +#include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_flag_parser.h" +#include "sanitizer_common/sanitizer_flags.h" + +// See comment below. +extern "C" { +extern void __cxa_atexit(void (*function)(void)); +} + +namespace __esan { + +bool EsanIsInitialized; +ToolType WhichTool; + +static const char EsanOptsEnv[] = "ESAN_OPTIONS"; + +// We are combining multiple performance tuning tools under the umbrella of +// one EfficiencySanitizer super-tool. Most of our tools have very similar +// memory access instrumentation, shadow memory mapping, libc interception, +// etc., and there is typically more shared code than distinct code. +// +// We are not willing to dispatch on tool dynamically in our fastpath +// instrumentation: thus, which tool to use is a static option selected +// at compile time and passed to __esan_init(). +// +// We are willing to pay the overhead of tool dispatch in the slowpath to more +// easily share code. We expect to only come here rarely. +// If this becomes a performance hit, we can add separate interface +// routines for each subtool (e.g., __esan_cache_frag_aligned_load_4). +// But for libc interceptors, we'll have to do one of the following: +// A) Add multiple-include support to sanitizer_common_interceptors.inc, +// instantiate it separately for each tool, and call the selected +// tool's intercept setup code. +// B) Build separate static runtime libraries, one for each tool. +// C) Completely split the tools into separate sanitizers. + +void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite) { + VPrintf(3, "in esan::%s %p: %c %p %d\n", __FUNCTION__, PC, + IsWrite ? 'w' : 'r', Addr, Size); + if (WhichTool == ESAN_CacheFrag) { + // TODO(bruening): add shadow mapping and update shadow bits here. + // We'll move this to cache_frag.cpp once we have something. + } +} + +static void initializeFlags() { + // Once we add our own flags we'll parse them here. + // For now the common ones are sufficient. + FlagParser Parser; + SetCommonFlagsDefaults(); + RegisterCommonFlags(&Parser); + Parser.ParseString(GetEnv(EsanOptsEnv)); + InitializeCommonFlags(); + if (Verbosity()) + ReportUnrecognizedFlags(); + if (common_flags()->help) + Parser.PrintFlagDescriptions(); + __sanitizer_set_report_path(common_flags()->log_path); +} + +void initializeLibrary(ToolType Tool) { + // We assume there is only one thread during init. + if (EsanIsInitialized) { + CHECK(Tool == WhichTool); + return; + } + WhichTool = Tool; + SanitizerToolName = "EfficiencySanitizer"; + initializeFlags(); + + // Intercepting libc _exit or exit via COMMON_INTERCEPTOR_ON_EXIT only + // finalizes on an explicit exit call by the app. To handle a normal + // exit we register an atexit handler. + ::__cxa_atexit((void (*)())finalizeLibrary); + + VPrintf(1, "in esan::%s\n", __FUNCTION__); + if (WhichTool != ESAN_CacheFrag) { + Printf("ERROR: unknown tool %d requested\n", WhichTool); + Die(); + } + + EsanIsInitialized = true; +} + +int finalizeLibrary() { + VPrintf(1, "in esan::%s\n", __FUNCTION__); + if (WhichTool == ESAN_CacheFrag) { + // FIXME NYI: we need to add sampling + callstack gathering and have a + // strategy for how to generate a final report. + // We'll move this to cache_frag.cpp once we have something. + Report("%s is not finished: nothing yet to report\n", SanitizerToolName); + } + return 0; +} + +} // namespace __esan diff --git a/lib/esan/esan.h b/lib/esan/esan.h new file mode 100644 index 000000000..fd69a6d61 --- /dev/null +++ b/lib/esan/esan.h @@ -0,0 +1,44 @@ +//===-- esan.h --------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Main internal esan header file. +// +// Ground rules: +// - C++ run-time should not be used (static CTORs, RTTI, exceptions, static +// function-scope locals) +// - All functions/classes/etc reside in namespace __esan, except for those +// declared in esan_interface_internal.h. +// - Platform-specific files should be used instead of ifdefs (*). +// - No system headers included in header files (*). +// - Platform specific headers included only into platform-specific files (*). +// +// (*) Except when inlining is critical for performance. +//===----------------------------------------------------------------------===// + +#ifndef ESAN_H +#define ESAN_H + +#include "sanitizer_common/sanitizer_common.h" +#include "esan_interface_internal.h" + +namespace __esan { + +extern bool EsanIsInitialized; + +extern ToolType WhichTool; + +void initializeLibrary(ToolType Tool); +int finalizeLibrary(); +void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite); + +} // namespace __esan + +#endif // ESAN_H diff --git a/lib/esan/esan.syms.extra b/lib/esan/esan.syms.extra new file mode 100644 index 000000000..bef023d5f --- /dev/null +++ b/lib/esan/esan.syms.extra @@ -0,0 +1,3 @@ +__esan_init +__esan_aligned* +__esan_unaligned* diff --git a/lib/esan/esan_interface.cpp b/lib/esan/esan_interface.cpp new file mode 100644 index 000000000..f8a562e55 --- /dev/null +++ b/lib/esan/esan_interface.cpp @@ -0,0 +1,102 @@ +//===-- esan_interface.cpp ------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +//===----------------------------------------------------------------------===// + +#include "esan_interface_internal.h" +#include "esan.h" +#include "sanitizer_common/sanitizer_internal_defs.h" + +using namespace __esan; // NOLINT + +void __esan_init(ToolType Tool) { + initializeLibrary(Tool); +} + +void __esan_aligned_load1(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, false); +} + +void __esan_aligned_load2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false); +} + +void __esan_aligned_load4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false); +} + +void __esan_aligned_load8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false); +} + +void __esan_aligned_load16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false); +} + +void __esan_aligned_store1(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, true); +} + +void __esan_aligned_store2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true); +} + +void __esan_aligned_store4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true); +} + +void __esan_aligned_store8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true); +} + +void __esan_aligned_store16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true); +} + +void __esan_unaligned_load2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false); +} + +void __esan_unaligned_load4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false); +} + +void __esan_unaligned_load8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false); +} + +void __esan_unaligned_load16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false); +} + +void __esan_unaligned_store2(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true); +} + +void __esan_unaligned_store4(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true); +} + +void __esan_unaligned_store8(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true); +} + +void __esan_unaligned_store16(void *Addr) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true); +} + +void __esan_unaligned_loadN(void *Addr, uptr Size) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, false); +} + +void __esan_unaligned_storeN(void *Addr, uptr Size) { + processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, true); +} diff --git a/lib/esan/esan_interface_internal.h b/lib/esan/esan_interface_internal.h new file mode 100644 index 000000000..a8b9e0887 --- /dev/null +++ b/lib/esan/esan_interface_internal.h @@ -0,0 +1,72 @@ +//===-- esan_interface_internal.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of EfficiencySanitizer, a family of performance tuners. +// +// Calls to the functions declared in this header will be inserted by +// the instrumentation module. +//===----------------------------------------------------------------------===// + +#ifndef ESAN_INTERFACE_INTERNAL_H +#define ESAN_INTERFACE_INTERNAL_H + +#include <sanitizer_common/sanitizer_internal_defs.h> + +// This header should NOT include any other headers. +// All functions in this header are extern "C" and start with __esan_. + +extern "C" { + +// This should be kept consistent with LLVM's EfficiencySanitizerOptions. +// The value is passed as a 32-bit integer by the compiler. +typedef enum Type : u32 { + ESAN_None = 0, + ESAN_CacheFrag, +} ToolType; + +// This function should be called at the very beginning of the process, +// before any instrumented code is executed and before any call to malloc. +SANITIZER_INTERFACE_ATTRIBUTE void __esan_init(ToolType Tool); + +// The instrumentation module will insert a call to one of these routines prior +// to each load and store instruction for which we do not have "fastpath" +// inlined instrumentation. These calls constitute the "slowpath" for our +// tools. We have separate routines for each type of memory access to enable +// targeted optimization. +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load1(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_load16(void *Addr); + +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store1(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_aligned_store16(void *Addr); + +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_load16(void *Addr); + +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store2(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store4(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store8(void *Addr); +SANITIZER_INTERFACE_ATTRIBUTE void __esan_unaligned_store16(void *Addr); + +// These cover unusually-sized accesses. +SANITIZER_INTERFACE_ATTRIBUTE +void __esan_unaligned_loadN(void *Addr, uptr Size); +SANITIZER_INTERFACE_ATTRIBUTE +void __esan_unaligned_storeN(void *Addr, uptr Size); + +} // extern "C" + +#endif // ESAN_INTERFACE_INTERNAL_H |