Skip to content

Commit af7aaae

Browse files
committed
[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 llvm-svn: 267060
1 parent 256c2e1 commit af7aaae

File tree

13 files changed

+476
-0
lines changed

13 files changed

+476
-0
lines changed

compiler-rt/cmake/config-ix.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
269269
${MIPS32} ${MIPS64} ${PPC64} ${S390X})
270270
set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
271271
set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64})
272+
set(ALL_ESAN_SUPPORTED_ARCH ${X86_64})
272273

273274
if(APPLE)
274275
include(CompilerRTDarwinUtils)
@@ -501,6 +502,9 @@ if(APPLE)
501502
list_intersect(CFI_SUPPORTED_ARCH
502503
ALL_CFI_SUPPORTED_ARCH
503504
SANITIZER_COMMON_SUPPORTED_ARCH)
505+
list_intersect(ESAN_SUPPORTED_ARCH
506+
ALL_ESAN_SUPPORTED_ARCH
507+
SANITIZER_COMMON_SUPPORTED_ARCH)
504508
else()
505509
# Architectures supported by compiler-rt libraries.
506510
filter_available_targets(BUILTIN_SUPPORTED_ARCH
@@ -523,6 +527,7 @@ else()
523527
filter_available_targets(SAFESTACK_SUPPORTED_ARCH
524528
${ALL_SAFESTACK_SUPPORTED_ARCH})
525529
filter_available_targets(CFI_SUPPORTED_ARCH ${ALL_CFI_SUPPORTED_ARCH})
530+
filter_available_targets(ESAN_SUPPORTED_ARCH ${ALL_ESAN_SUPPORTED_ARCH})
526531
endif()
527532

528533
if (MSVC)
@@ -630,3 +635,10 @@ if (COMPILER_RT_HAS_SANITIZER_COMMON AND CFI_SUPPORTED_ARCH AND
630635
else()
631636
set(COMPILER_RT_HAS_CFI FALSE)
632637
endif()
638+
639+
if (COMPILER_RT_HAS_SANITIZER_COMMON AND ESAN_SUPPORTED_ARCH AND
640+
OS_NAME MATCHES "Linux")
641+
set(COMPILER_RT_HAS_ESAN TRUE)
642+
else()
643+
set(COMPILER_RT_HAS_ESAN FALSE)
644+
endif()

compiler-rt/lib/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,8 @@ if(COMPILER_RT_BUILD_SANITIZERS)
4848
if(COMPILER_RT_HAS_CFI)
4949
add_subdirectory(cfi)
5050
endif()
51+
52+
if(COMPILER_RT_HAS_ESAN)
53+
add_subdirectory(esan)
54+
endif()
5155
endif()

compiler-rt/lib/esan/CMakeLists.txt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Build for the EfficiencySanitizer runtime support library.
2+
3+
add_custom_target(esan)
4+
5+
set(ESAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
6+
append_rtti_flag(OFF ESAN_RTL_CFLAGS)
7+
8+
include_directories(..)
9+
10+
set(ESAN_SOURCES
11+
esan.cpp
12+
esan_interface.cpp)
13+
14+
foreach (arch ${ESAN_SUPPORTED_ARCH})
15+
add_compiler_rt_runtime(clang_rt.esan
16+
STATIC
17+
ARCHS ${arch}
18+
SOURCES ${ESAN_SOURCES}
19+
$<TARGET_OBJECTS:RTInterception.${arch}>
20+
$<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
21+
$<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
22+
CFLAGS ${ESAN_RTL_CFLAGS})
23+
add_sanitizer_rt_symbols(clang_rt.esan
24+
ARCHS ${arch}
25+
EXTRA esan.syms.extra)
26+
add_dependencies(esan
27+
clang_rt.esan-${arch}
28+
clang_rt.esan-${arch}-symbols)
29+
endforeach()
30+
31+
add_dependencies(compiler-rt esan)
32+
33+
if (COMPILER_RT_INCLUDE_TESTS)
34+
# TODO(bruening): add tests via add_subdirectory(tests)
35+
endif()

compiler-rt/lib/esan/esan.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//===-- esan.cpp ----------------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of EfficiencySanitizer, a family of performance tuners.
11+
//
12+
// Main file (entry points) for the Esan run-time.
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "esan.h"
16+
#include "esan_interface_internal.h"
17+
#include "sanitizer_common/sanitizer_common.h"
18+
#include "sanitizer_common/sanitizer_flag_parser.h"
19+
#include "sanitizer_common/sanitizer_flags.h"
20+
21+
// See comment below.
22+
extern "C" {
23+
extern void __cxa_atexit(void (*function)(void));
24+
}
25+
26+
namespace __esan {
27+
28+
bool EsanIsInitialized;
29+
ToolType WhichTool;
30+
31+
static const char EsanOptsEnv[] = "ESAN_OPTIONS";
32+
33+
// We are combining multiple performance tuning tools under the umbrella of
34+
// one EfficiencySanitizer super-tool. Most of our tools have very similar
35+
// memory access instrumentation, shadow memory mapping, libc interception,
36+
// etc., and there is typically more shared code than distinct code.
37+
//
38+
// We are not willing to dispatch on tool dynamically in our fastpath
39+
// instrumentation: thus, which tool to use is a static option selected
40+
// at compile time and passed to __esan_init().
41+
//
42+
// We are willing to pay the overhead of tool dispatch in the slowpath to more
43+
// easily share code. We expect to only come here rarely.
44+
// If this becomes a performance hit, we can add separate interface
45+
// routines for each subtool (e.g., __esan_cache_frag_aligned_load_4).
46+
// But for libc interceptors, we'll have to do one of the following:
47+
// A) Add multiple-include support to sanitizer_common_interceptors.inc,
48+
// instantiate it separately for each tool, and call the selected
49+
// tool's intercept setup code.
50+
// B) Build separate static runtime libraries, one for each tool.
51+
// C) Completely split the tools into separate sanitizers.
52+
53+
void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite) {
54+
VPrintf(3, "in esan::%s %p: %c %p %d\n", __FUNCTION__, PC,
55+
IsWrite ? 'w' : 'r', Addr, Size);
56+
if (WhichTool == ESAN_CacheFrag) {
57+
// TODO(bruening): add shadow mapping and update shadow bits here.
58+
// We'll move this to cache_frag.cpp once we have something.
59+
}
60+
}
61+
62+
static void initializeFlags() {
63+
// Once we add our own flags we'll parse them here.
64+
// For now the common ones are sufficient.
65+
FlagParser Parser;
66+
SetCommonFlagsDefaults();
67+
RegisterCommonFlags(&Parser);
68+
Parser.ParseString(GetEnv(EsanOptsEnv));
69+
InitializeCommonFlags();
70+
if (Verbosity())
71+
ReportUnrecognizedFlags();
72+
if (common_flags()->help)
73+
Parser.PrintFlagDescriptions();
74+
__sanitizer_set_report_path(common_flags()->log_path);
75+
}
76+
77+
void initializeLibrary(ToolType Tool) {
78+
// We assume there is only one thread during init.
79+
if (EsanIsInitialized) {
80+
CHECK(Tool == WhichTool);
81+
return;
82+
}
83+
WhichTool = Tool;
84+
SanitizerToolName = "EfficiencySanitizer";
85+
initializeFlags();
86+
87+
// Intercepting libc _exit or exit via COMMON_INTERCEPTOR_ON_EXIT only
88+
// finalizes on an explicit exit call by the app. To handle a normal
89+
// exit we register an atexit handler.
90+
::__cxa_atexit((void (*)())finalizeLibrary);
91+
92+
VPrintf(1, "in esan::%s\n", __FUNCTION__);
93+
if (WhichTool != ESAN_CacheFrag) {
94+
Printf("ERROR: unknown tool %d requested\n", WhichTool);
95+
Die();
96+
}
97+
98+
EsanIsInitialized = true;
99+
}
100+
101+
int finalizeLibrary() {
102+
VPrintf(1, "in esan::%s\n", __FUNCTION__);
103+
if (WhichTool == ESAN_CacheFrag) {
104+
// FIXME NYI: we need to add sampling + callstack gathering and have a
105+
// strategy for how to generate a final report.
106+
// We'll move this to cache_frag.cpp once we have something.
107+
Report("%s is not finished: nothing yet to report\n", SanitizerToolName);
108+
}
109+
return 0;
110+
}
111+
112+
} // namespace __esan

compiler-rt/lib/esan/esan.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===-- esan.h --------------------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of EfficiencySanitizer, a family of performance tuners.
11+
//
12+
// Main internal esan header file.
13+
//
14+
// Ground rules:
15+
// - C++ run-time should not be used (static CTORs, RTTI, exceptions, static
16+
// function-scope locals)
17+
// - All functions/classes/etc reside in namespace __esan, except for those
18+
// declared in esan_interface_internal.h.
19+
// - Platform-specific files should be used instead of ifdefs (*).
20+
// - No system headers included in header files (*).
21+
// - Platform specific headers included only into platform-specific files (*).
22+
//
23+
// (*) Except when inlining is critical for performance.
24+
//===----------------------------------------------------------------------===//
25+
26+
#ifndef ESAN_H
27+
#define ESAN_H
28+
29+
#include "sanitizer_common/sanitizer_common.h"
30+
#include "esan_interface_internal.h"
31+
32+
namespace __esan {
33+
34+
extern bool EsanIsInitialized;
35+
36+
extern ToolType WhichTool;
37+
38+
void initializeLibrary(ToolType Tool);
39+
int finalizeLibrary();
40+
void processRangeAccess(uptr PC, uptr Addr, int Size, bool IsWrite);
41+
42+
} // namespace __esan
43+
44+
#endif // ESAN_H

compiler-rt/lib/esan/esan.syms.extra

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__esan_init
2+
__esan_aligned*
3+
__esan_unaligned*
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//===-- esan_interface.cpp ------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file is a part of EfficiencySanitizer, a family of performance tuners.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "esan_interface_internal.h"
15+
#include "esan.h"
16+
#include "sanitizer_common/sanitizer_internal_defs.h"
17+
18+
using namespace __esan; // NOLINT
19+
20+
void __esan_init(ToolType Tool) {
21+
initializeLibrary(Tool);
22+
}
23+
24+
void __esan_aligned_load1(void *Addr) {
25+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, false);
26+
}
27+
28+
void __esan_aligned_load2(void *Addr) {
29+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false);
30+
}
31+
32+
void __esan_aligned_load4(void *Addr) {
33+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false);
34+
}
35+
36+
void __esan_aligned_load8(void *Addr) {
37+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false);
38+
}
39+
40+
void __esan_aligned_load16(void *Addr) {
41+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false);
42+
}
43+
44+
void __esan_aligned_store1(void *Addr) {
45+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 1, true);
46+
}
47+
48+
void __esan_aligned_store2(void *Addr) {
49+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true);
50+
}
51+
52+
void __esan_aligned_store4(void *Addr) {
53+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true);
54+
}
55+
56+
void __esan_aligned_store8(void *Addr) {
57+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true);
58+
}
59+
60+
void __esan_aligned_store16(void *Addr) {
61+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true);
62+
}
63+
64+
void __esan_unaligned_load2(void *Addr) {
65+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, false);
66+
}
67+
68+
void __esan_unaligned_load4(void *Addr) {
69+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, false);
70+
}
71+
72+
void __esan_unaligned_load8(void *Addr) {
73+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, false);
74+
}
75+
76+
void __esan_unaligned_load16(void *Addr) {
77+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, false);
78+
}
79+
80+
void __esan_unaligned_store2(void *Addr) {
81+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 2, true);
82+
}
83+
84+
void __esan_unaligned_store4(void *Addr) {
85+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 4, true);
86+
}
87+
88+
void __esan_unaligned_store8(void *Addr) {
89+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 8, true);
90+
}
91+
92+
void __esan_unaligned_store16(void *Addr) {
93+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, 16, true);
94+
}
95+
96+
void __esan_unaligned_loadN(void *Addr, uptr Size) {
97+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, false);
98+
}
99+
100+
void __esan_unaligned_storeN(void *Addr, uptr Size) {
101+
processRangeAccess(GET_CALLER_PC(), (uptr)Addr, Size, true);
102+
}

0 commit comments

Comments
 (0)