Skip to content

Instantly share code, notes, and snippets.

@Enna1
Created June 1, 2022 03:58
Show Gist options
  • Save Enna1/f8696072bd9dc36ac236ba63839b7c16 to your computer and use it in GitHub Desktop.
Save Enna1/f8696072bd9dc36ac236ba63839b7c16 to your computer and use it in GitHub Desktop.
commit 3a87bff1977a02feb072a14930add69ff47cf08d
Author: Enna1 <xumingjie.enna1@bytedance.com>
Date: Tue May 31 12:06:41 2022 +0800
DumbSanitizer
diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def
index 9b8936cc520c..6aa6e24d4ec4 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -73,6 +73,9 @@ SANITIZER("fuzzer-no-link", FuzzerNoLink)
// ThreadSanitizer
SANITIZER("thread", Thread)
+// DumbSanitizer
+SANITIZER("dumb", Dumb)
+
// LeakSanitizer
SANITIZER("leak", Leak)
diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index d288b0151c9f..a885d68f81dd 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -80,6 +80,7 @@ public:
return needsHwasanRt() && HwasanUseAliases;
}
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
+ bool needsDbsanRt() const { return Sanitizers.has(SanitizerKind::Dumb); }
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
bool needsLsanRt() const {
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index a4d330c0ba93..fd4bff63a3d7 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -68,6 +68,7 @@
#include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h"
#include "llvm/Transforms/Instrumentation/BoundsChecking.h"
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
+#include "llvm/Transforms/Instrumentation/DumbSanitizer.h"
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
@@ -390,6 +391,11 @@ static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
PM.add(createThreadSanitizerLegacyPassPass());
}
+static void addDumbSanitizerPass(const PassManagerBuilder &Builder,
+ legacy::PassManagerBase &PM) {
+ PM.add(createDumbSanitizerLegacyPassPass());
+}
+
static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder,
legacy::PassManagerBase &PM) {
const PassManagerBuilderWrapper &BuilderWrapper =
@@ -834,6 +840,13 @@ void EmitAssemblyHelper::CreatePasses(legacy::PassManager &MPM,
addThreadSanitizerPass);
}
+ if (LangOpts.Sanitize.has(SanitizerKind::Dumb)) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
+ addDumbSanitizerPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
+ addDumbSanitizerPass);
+ }
+
if (LangOpts.Sanitize.has(SanitizerKind::DataFlow)) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addDataFlowSanitizerPass);
@@ -1194,6 +1207,11 @@ static void addSanitizers(const Triple &TargetTriple,
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
+ if (LangOpts.Sanitize.has(SanitizerKind::Dumb)) {
+ MPM.addPass(ModuleDumbSanitizerPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(DumbSanitizerPass()));
+ }
+
auto ASanPass = [&](SanitizerMask Mask, bool CompileKernel) {
if (LangOpts.Sanitize.has(Mask)) {
bool UseGlobalGC = asanUseGlobalsGC(TargetTriple, CodeGenOpts);
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 8f9244cae8db..37c2cf724fc3 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -845,6 +845,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
}
if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
SharedRuntimes.push_back("tsan");
+ if (SanArgs.needsDbsanRt() && SanArgs.linkRuntimes())
+ SharedRuntimes.push_back("dbsan");
if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsHwasanAliasesRt())
SharedRuntimes.push_back("hwasan_aliases");
@@ -896,6 +898,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
}
if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes())
StaticRuntimes.push_back("dfsan");
+ if (SanArgs.needsDbsanRt() && SanArgs.linkRuntimes())
+ StaticRuntimes.push_back("dbsan");
if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes())
StaticRuntimes.push_back("lsan");
if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) {
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 83cb41159de7..82936d06cdb1 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -719,6 +719,8 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::Leak;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ)
Res |= SanitizerKind::Thread;
+ if (IsX86_64)
+ Res |= SanitizerKind::Dumb;
if (IsX86_64)
Res |= SanitizerKind::KernelMemory;
if (IsX86 || IsX86_64)
diff --git a/clang/runtime/CMakeLists.txt b/clang/runtime/CMakeLists.txt
index ca7e17927ee1..afd58a1412a1 100644
--- a/clang/runtime/CMakeLists.txt
+++ b/clang/runtime/CMakeLists.txt
@@ -119,7 +119,7 @@ if(LLVM_BUILD_EXTERNAL_COMPILER_RT AND EXISTS ${COMPILER_RT_SRC_ROOT}/)
COMPONENT compiler-rt)
# Add top-level targets that build specific compiler-rt runtimes.
- set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan ubsan ubsan-minimal)
+ set(COMPILER_RT_RUNTIMES fuzzer asan builtins dfsan lsan msan profile tsan dbsan ubsan ubsan-minimal)
foreach(runtime ${COMPILER_RT_RUNTIMES})
get_ext_project_build_command(build_runtime_cmd ${runtime})
add_custom_target(${runtime}
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index 3e86cf63c789..e67342c7c5c1 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -60,6 +60,7 @@ set(ALL_MEMPROF_SUPPORTED_ARCH ${X86_64})
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC32} ${PPC64}
${MIPS32} ${MIPS64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON})
set(ALL_TSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X})
+set(ALL_DBSAN_SUPPORTED_ARCH ${X86} ${X86_64})
set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON})
set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64}
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index fc62d5ecc0a9..3e8563e8c2d4 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -570,6 +570,9 @@ if(APPLE)
list_intersect(TSAN_SUPPORTED_ARCH
ALL_TSAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
+ list_intersect(DBSAN_SUPPORTED_ARCH
+ ALL_DBSAN_SUPPORTED_ARCH
+ SANITIZER_COMMON_SUPPORTED_ARCH)
list_intersect(UBSAN_SUPPORTED_ARCH
ALL_UBSAN_SUPPORTED_ARCH
SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -618,6 +621,7 @@ else()
filter_available_targets(MEMPROF_SUPPORTED_ARCH ${ALL_MEMPROF_SUPPORTED_ARCH})
filter_available_targets(PROFILE_SUPPORTED_ARCH ${ALL_PROFILE_SUPPORTED_ARCH})
filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH})
+ filter_available_targets(DBSAN_SUPPORTED_ARCH ${ALL_DBSAN_SUPPORTED_ARCH})
filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH})
filter_available_targets(SAFESTACK_SUPPORTED_ARCH
${ALL_SAFESTACK_SUPPORTED_ARCH})
@@ -662,7 +666,7 @@ if(COMPILER_RT_SUPPORTED_ARCH)
endif()
message(STATUS "Compiler-RT supported architectures: ${COMPILER_RT_SUPPORTED_ARCH}")
-set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;safestack;cfi;scudo;ubsan_minimal;gwp_asan)
+set(ALL_SANITIZERS asan;dfsan;msan;hwasan;tsan;dbsan;safestack;cfi;scudo;ubsan_minimal;gwp_asan)
set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
"sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
@@ -762,6 +766,19 @@ else()
set(COMPILER_RT_TSAN_HAS_STATIC_RUNTIME FALSE)
endif()
+if (COMPILER_RT_HAS_SANITIZER_COMMON AND DBSAN_SUPPORTED_ARCH AND
+ OS_NAME MATCHES "Linux")
+ set(COMPILER_RT_HAS_DBSAN TRUE)
+else()
+ set(COMPILER_RT_HAS_DBSAN FALSE)
+endif()
+
+if (OS_NAME MATCHES "Linux")
+ set(COMPILER_RT_DBSAN_HAS_STATIC_RUNTIME TRUE)
+else()
+ set(COMPILER_RT_DBSAN_HAS_STATIC_RUNTIME FALSE)
+endif()
+
if (COMPILER_RT_HAS_SANITIZER_COMMON AND UBSAN_SUPPORTED_ARCH AND
OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|Windows|Android|Fuchsia|SunOS")
set(COMPILER_RT_HAS_UBSAN TRUE)
diff --git a/compiler-rt/lib/dbsan/CMakeLists.txt b/compiler-rt/lib/dbsan/CMakeLists.txt
new file mode 100644
index 000000000000..b6c9ed649968
--- /dev/null
+++ b/compiler-rt/lib/dbsan/CMakeLists.txt
@@ -0,0 +1,47 @@
+include_directories(..)
+
+# Runtime library sources and build flags.
+set(DBSAN_RTL_SOURCES
+ dbsan_flags.cpp
+ dbsan_interface.cpp
+ dbsan_rtl.cpp
+ )
+
+set(DBSAN_RTL_HEADERS
+ dbsan_flags.h
+ dbsan_interface.h
+ dbsan_rtl.h
+ )
+
+set(DBSAN_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_rtti_flag(OFF DBSAN_COMMON_CFLAGS)
+# Prevent clang from generating libc calls.
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding DBSAN_COMMON_CFLAGS)
+
+# Too many existing bugs, needs cleanup.
+append_list_if(COMPILER_RT_HAS_WNO_FORMAT -Wno-format DBSAN_COMMON_CFLAGS)
+
+# Static runtime library.
+add_compiler_rt_component(dbsan)
+
+foreach(arch ${DBSAN_SUPPORTED_ARCH})
+ set(DBSAN_CFLAGS ${DBSAN_COMMON_CFLAGS})
+ append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE DBSAN_CFLAGS)
+ add_compiler_rt_runtime(clang_rt.dbsan
+ STATIC
+ ARCHS ${arch}
+ SOURCES ${DBSAN_RTL_SOURCES}
+ $<TARGET_OBJECTS:RTInterception.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
+ ADDITIONAL_HEADERS ${DBSAN_RTL_HEADERS}
+ CFLAGS ${DBSAN_CFLAGS}
+ PARENT_TARGET dbsan)
+ add_sanitizer_rt_symbols(clang_rt.dbsan
+ ARCHS ${arch}
+ EXTRA dbsan.syms.extra)
+ add_dependencies(dbsan
+ clang_rt.dbsan-${arch}-symbols)
+endforeach()
+
diff --git a/compiler-rt/lib/dbsan/dbsan.syms.extra b/compiler-rt/lib/dbsan/dbsan.syms.extra
new file mode 100644
index 000000000000..561a73aa1369
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan.syms.extra
@@ -0,0 +1,3 @@
+__dbsan_init
+__dbsan_read*
+__dbsan_write*
diff --git a/compiler-rt/lib/dbsan/dbsan_flags.cpp b/compiler-rt/lib/dbsan/dbsan_flags.cpp
new file mode 100644
index 000000000000..cacc4f07bf9c
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan_flags.cpp
@@ -0,0 +1,47 @@
+//===-- dbsan_flags.cpp --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DumbSanitizer.
+//
+// DbSan flag parsing logic.
+//===----------------------------------------------------------------------===//
+
+#include "dbsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace __dbsan {
+
+Flags dbsan_flags_dont_use_directly; // use via flags().
+
+void Flags::SetDefaults() {
+#define DBSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "dbsan_flags.inc"
+#undef DBSAN_FLAG
+}
+
+static void RegisterDbSanFlags(__sanitizer::FlagParser *parser, Flags *f) {
+#define DBSAN_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "dbsan_flags.inc"
+#undef DBSAN_FLAG
+}
+
+void InitializeFlags() {
+ Flags *f = flags();
+ f->SetDefaults();
+
+ __sanitizer::FlagParser dbsan_parser;
+ RegisterDbSanFlags(&dbsan_parser, f);
+
+ // Override from command line.
+ dbsan_parser.ParseStringFromEnv("DBSAN_OPTIONS");
+}
+
+} // namespace __dbsan
diff --git a/compiler-rt/lib/dbsan/dbsan_flags.h b/compiler-rt/lib/dbsan/dbsan_flags.h
new file mode 100644
index 000000000000..4803ec8fc830
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan_flags.h
@@ -0,0 +1,37 @@
+//===-- dbsan_flags.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DumbSanitizer.
+//
+// DumbSanitizer runtime flags.
+//===----------------------------------------------------------------------===//
+
+#ifndef DBSAN_FLAGS_H
+#define DBSAN_FLAGS_H
+
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __dbsan {
+
+struct Flags {
+#define DBSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "dbsan_flags.inc"
+#undef DBSAN_FLAG
+
+ void SetDefaults();
+};
+
+extern Flags dbsan_flags_dont_use_directly;
+inline Flags *flags() { return &dbsan_flags_dont_use_directly; }
+
+void InitializeFlags();
+
+} // namespace __dbsan
+
+#endif // DBSAN_FLAGS_H
diff --git a/compiler-rt/lib/dbsan/dbsan_flags.inc b/compiler-rt/lib/dbsan/dbsan_flags.inc
new file mode 100644
index 000000000000..b4fc06cfa0a0
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan_flags.inc
@@ -0,0 +1,19 @@
+//===-- dbsan_flags.inc ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// DbSan runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef DBSAN_FLAG
+# error "Define DBSAN_FLAG prior to including this file!"
+#endif
+
+// DBSAN_FLAG(Type, Name, DefaultValue, Description)
+
+DBSAN_FLAG(bool, verbose, false, "Print runtime loginfo.")
+DBSAN_FLAG(bool, print_frequent_access, false, "Print most frequently access info at exit.")
diff --git a/compiler-rt/lib/dbsan/dbsan_interface.cpp b/compiler-rt/lib/dbsan/dbsan_interface.cpp
new file mode 100644
index 000000000000..c977d812d5e6
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan_interface.cpp
@@ -0,0 +1,39 @@
+//===-- dbsan_interface.cpp
+//------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DumbSanitizer (DbSan).
+//
+//===----------------------------------------------------------------------===//
+
+#include "dbsan_interface.h"
+#include "dbsan_rtl.h"
+
+using namespace __dbsan;
+
+void __dbsan_init() { Initialize(); }
+
+void __dbsan_read1(void *addr) { MemoryAccess((uptr)addr, 1, kAccessRead); }
+
+void __dbsan_read2(void *addr) { MemoryAccess((uptr)addr, 2, kAccessRead); }
+
+void __dbsan_read4(void *addr) { MemoryAccess((uptr)addr, 4, kAccessRead); }
+
+void __dbsan_read8(void *addr) { MemoryAccess((uptr)addr, 8, kAccessRead); }
+
+void __dbsan_read16(void *addr) { MemoryAccess((uptr)addr, 16, kAccessRead); }
+
+void __dbsan_write1(void *addr) { MemoryAccess((uptr)addr, 1, kAccessWrite); }
+
+void __dbsan_write2(void *addr) { MemoryAccess((uptr)addr, 2, kAccessWrite); }
+
+void __dbsan_write4(void *addr) { MemoryAccess((uptr)addr, 4, kAccessWrite); }
+
+void __dbsan_write8(void *addr) { MemoryAccess((uptr)addr, 8, kAccessWrite); }
+
+void __dbsan_write16(void *addr) { MemoryAccess((uptr)addr, 16, kAccessWrite); }
\ No newline at end of file
diff --git a/compiler-rt/lib/dbsan/dbsan_interface.h b/compiler-rt/lib/dbsan/dbsan_interface.h
new file mode 100644
index 000000000000..2157cc3bfb54
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan_interface.h
@@ -0,0 +1,45 @@
+//===-- dbsan_interface.h ----------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DumbSanitizer (DbSan).
+//
+// The functions declared in this header will be inserted by the instrumentation
+// module.
+//===----------------------------------------------------------------------===//
+#ifndef DBSAN_INTERFACE_H
+#define DBSAN_INTERFACE_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 __dbsan_.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_init();
+
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_read1(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_read2(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_read4(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_read8(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_read16(void *addr);
+
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_write1(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_write2(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_write4(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_write8(void *addr);
+SANITIZER_INTERFACE_ATTRIBUTE void __dbsan_write16(void *addr);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // DBSAN_INTERFACE_H
\ No newline at end of file
diff --git a/compiler-rt/lib/dbsan/dbsan_rtl.cpp b/compiler-rt/lib/dbsan/dbsan_rtl.cpp
new file mode 100644
index 000000000000..65efc1c3a6e4
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan_rtl.cpp
@@ -0,0 +1,77 @@
+//===-- dbsan_rtl.cpp
+//------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DumbSanitizer (DbSan).
+//
+// Main file (entry points) for the DbSan run-time.
+//===----------------------------------------------------------------------===//
+
+#include "dbsan_rtl.h"
+#include "dbsan_flags.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+
+namespace __dbsan {
+
+static void dbsan_atexit() {
+ __sanitizer::Printf(
+ "#Most frequently accessed address: %p, access count: %zd\n",
+ (void *)ctx->most_frequently_accessed_addr,
+ ctx->most_frequently_accessed_count);
+}
+
+static char ctx_placeholder[sizeof(Context)] ALIGNED(SANITIZER_CACHE_LINE_SIZE);
+Context *ctx;
+
+void Initialize() {
+ InitializeFlags();
+ if (flags()->print_frequent_access)
+ __sanitizer::Atexit(dbsan_atexit);
+ ctx = new (ctx_placeholder) Context;
+}
+
+ALWAYS_INLINE USED void MemoryAccess(uptr addr, uptr size, AccessType typ) {
+ if (flags()->verbose) {
+ __sanitizer::Printf("#Memory Access: %p/%zd typ=0x%x\n", (void *)addr, size,
+ static_cast<int>(typ));
+ }
+
+ uptr access_count = 0;
+ switch (size) {
+ case 1:
+ ctx->rw1_count[addr]++;
+ access_count = ctx->rw1_count[addr];
+ break;
+ case 2:
+ ctx->rw2_count[addr]++;
+ access_count = ctx->rw2_count[addr];
+ break;
+ case 4:
+ ctx->rw4_count[addr]++;
+ access_count = ctx->rw4_count[addr];
+ break;
+ case 8:
+ ctx->rw8_count[addr]++;
+ access_count = ctx->rw8_count[addr];
+ break;
+ case 16:
+ ctx->rw16_count[addr]++;
+ access_count = ctx->rw16_count[addr];
+ break;
+ default:
+ break;
+ }
+
+ if (access_count > ctx->most_frequently_accessed_count) {
+ ctx->most_frequently_accessed_count = access_count;
+ ctx->most_frequently_accessed_addr = addr;
+ }
+}
+
+} // namespace __dbsan
\ No newline at end of file
diff --git a/compiler-rt/lib/dbsan/dbsan_rtl.h b/compiler-rt/lib/dbsan/dbsan_rtl.h
new file mode 100644
index 000000000000..61ae15e84713
--- /dev/null
+++ b/compiler-rt/lib/dbsan/dbsan_rtl.h
@@ -0,0 +1,52 @@
+//===-- dbsan_rtl.h ----------------------------------------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DumbSanitizer (DbSan).
+//
+// Main internal DbSan header file.
+//===----------------------------------------------------------------------===//
+
+#ifndef DBSAN_RTL_H
+#define DBSAN_RTL_H
+
+#include "sanitizer_common/sanitizer_dense_map.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+namespace __dbsan {
+
+using __sanitizer::uptr;
+typedef uptr AccessType;
+enum : AccessType {
+ kAccessWrite = 0,
+ kAccessRead = 1 << 0,
+};
+
+struct Context {
+ Context()
+ : initialized(), most_frequently_accessed_addr(),
+ most_frequently_accessed_count(), rw1_count(), rw2_count(), rw4_count(),
+ rw8_count(), rw16_count(){};
+ bool initialized;
+ uptr most_frequently_accessed_addr;
+ uptr most_frequently_accessed_count;
+ __sanitizer::DenseMap<uptr, uptr> rw1_count;
+ __sanitizer::DenseMap<uptr, uptr> rw2_count;
+ __sanitizer::DenseMap<uptr, uptr> rw4_count;
+ __sanitizer::DenseMap<uptr, uptr> rw8_count;
+ __sanitizer::DenseMap<uptr, uptr> rw16_count;
+};
+
+extern Context *ctx; // The one and the only global runtime context.
+
+void Initialize();
+void MemoryAccess(uptr addr, uptr size, AccessType typ);
+
+} // namespace __dbsan
+
+#endif
\ No newline at end of file
diff --git a/compiler-rt/test/dbsan/CMakeLists.txt b/compiler-rt/test/dbsan/CMakeLists.txt
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 489ef045796f..a101b96167b6 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -143,6 +143,7 @@ void initializeDomPrinterPass(PassRegistry&);
void initializeDomViewerPass(PassRegistry&);
void initializeDominanceFrontierWrapperPassPass(PassRegistry&);
void initializeDominatorTreeWrapperPassPass(PassRegistry&);
+void initializeDumbSanitizerLegacyPassPass(PassRegistry &);
void initializeDwarfEHPrepareLegacyPassPass(PassRegistry &);
void initializeEarlyCSELegacyPassPass(PassRegistry&);
void initializeEarlyCSEMemSSALegacyPassPass(PassRegistry&);
diff --git a/llvm/include/llvm/Transforms/Instrumentation/DumbSanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/DumbSanitizer.h
new file mode 100644
index 000000000000..024a89d7c2b6
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Instrumentation/DumbSanitizer.h
@@ -0,0 +1,41 @@
+//===--------- Definition of the DumbSanitizer class --------------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the dumb sanitizer pass.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TRANSFORMS_INSTRUMENTATION_DUMBSANITIZER_H
+#define LLVM_TRANSFORMS_INSTRUMENTATION_DUMBSANITIZER_H
+
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Pass.h"
+
+namespace llvm {
+// Insert DumbSanitizer instrumentation
+FunctionPass *createDumbSanitizerLegacyPassPass();
+
+// A function pass for dbsan instrumentation.
+/// Inserts calls to runtime library functions.
+struct DumbSanitizerPass : public PassInfoMixin<DumbSanitizerPass> {
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+ static bool isRequired() { return true; }
+};
+
+/// A module pass for dbsan instrumentation.
+/// Create ctor and init functions.
+struct ModuleDumbSanitizerPass : public PassInfoMixin<ModuleDumbSanitizerPass> {
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+ static bool isRequired() { return true; }
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
index 3b29c3df6429..8830152f2988 100644
--- a/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
+++ b/llvm/lib/Transforms/Instrumentation/CMakeLists.txt
@@ -4,6 +4,7 @@ add_llvm_component_library(LLVMInstrumentation
CGProfile.cpp
ControlHeightReduction.cpp
DataFlowSanitizer.cpp
+ DumbSanitizer.cpp
GCOVProfiling.cpp
MemProfiler.cpp
MemorySanitizer.cpp
diff --git a/llvm/lib/Transforms/Instrumentation/DumbSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DumbSanitizer.cpp
new file mode 100644
index 000000000000..ea6331948c4d
--- /dev/null
+++ b/llvm/lib/Transforms/Instrumentation/DumbSanitizer.cpp
@@ -0,0 +1,271 @@
+//===- DumbSanitizer.cpp - dumb memory access profiler ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DumbSanitizer. Memory accesses are instrumented
+// to calls to run-time library which increment the access count held in a map.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Instrumentation/DumbSanitizer.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "dbsan"
+
+const char kDbsanModuleCtorName[] = "dbsan.module_ctor";
+const char kDbsanInitName[] = "__dbsan_init";
+
+// Command-line flags.
+
+static cl::opt<bool> ClInstrumentReads("dbsan-instrument-reads",
+ cl::desc("instrument read instructions"),
+ cl::Hidden, cl::init(true));
+
+static cl::opt<bool>
+ ClInstrumentWrites("dbsan-instrument-writes",
+ cl::desc("instrument write instructions"), cl::Hidden,
+ cl::init(true));
+
+STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
+STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
+
+namespace {
+
+struct InterestingMemoryAccess {
+ Value *Addr = nullptr;
+ bool IsWrite;
+ unsigned Alignment;
+ Type *AccessTy;
+ uint64_t TypeSize;
+};
+
+/// Instrument the code in module to profile memory accesses.
+class DumbSanitizer {
+public:
+ DumbSanitizer(Module &M) { C = &(M.getContext()); }
+
+ bool sanitizeFunction(Function &F);
+
+private:
+ void initializeCallbacks(Module &M);
+ int getMemoryAccessFuncIndex(uint32_t TypeSize);
+ /// If it is an interesting memory access, populate information
+ /// about the access and return a InterestingMemoryAccess struct.
+ /// Otherwise return None.
+ Optional<InterestingMemoryAccess>
+ isInterestingMemoryAccess(Instruction *I) const;
+ void instrumentMemoryAccess(Instruction *I, const DataLayout &DL,
+ InterestingMemoryAccess &Access);
+
+ LLVMContext *C;
+ int LongSize;
+ Type *IntptrTy;
+ // Accesses sizes are powers of two: 1, 2, 4, 8, 16.
+ static const size_t kNumberOfAccessSizes = 5;
+ FunctionCallee DbsanRead[kNumberOfAccessSizes];
+ FunctionCallee DbsanWrite[kNumberOfAccessSizes];
+ Value *DynamicShadowOffset = nullptr;
+};
+
+struct DumbSanitizerLegacyPass : public FunctionPass {
+ DumbSanitizerLegacyPass() : FunctionPass(ID) {
+ initializeDumbSanitizerLegacyPassPass(*PassRegistry::getPassRegistry());
+ }
+ StringRef getPassName() const override;
+ bool doInitialization(Module &M) override;
+ bool runOnFunction(Function &F) override;
+ static char ID;
+
+private:
+ Optional<DumbSanitizer> DbSan;
+};
+
+void insertModuleCtor(Module &M) {
+ getOrCreateSanitizerCtorAndInitFunctions(
+ M, kDbsanModuleCtorName, kDbsanInitName, /*InitArgTypes=*/{},
+ /*InitArgs=*/{},
+ // This callback is invoked when the functions are created the first
+ // time. Hook them into the global ctors list in that case:
+ [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); });
+}
+
+} // end anonymous namespace
+
+PreservedAnalyses DumbSanitizerPass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ DumbSanitizer DbSan(*F.getParent());
+ if (DbSan.sanitizeFunction(F))
+ return PreservedAnalyses::none();
+ return PreservedAnalyses::all();
+}
+
+PreservedAnalyses ModuleDumbSanitizerPass::run(Module &M,
+ ModuleAnalysisManager &MAM) {
+ insertModuleCtor(M);
+ return PreservedAnalyses::none();
+}
+
+char DumbSanitizerLegacyPass::ID = 0;
+INITIALIZE_PASS_BEGIN(DumbSanitizerLegacyPass, "dbsan",
+ "DumbSanitizer: profile memory accesses.", false, false)
+INITIALIZE_PASS_END(DumbSanitizerLegacyPass, "dbsan",
+ "DumbSanitizer: profile memory accesses.", false, false)
+
+StringRef DumbSanitizerLegacyPass::getPassName() const {
+ return "DumbSanitizerLegacyPass";
+}
+
+bool DumbSanitizerLegacyPass::doInitialization(Module &M) {
+ insertModuleCtor(M);
+ DbSan.emplace(M);
+ return true;
+}
+
+bool DumbSanitizerLegacyPass::runOnFunction(Function &F) {
+ return DbSan->sanitizeFunction(F);
+}
+
+FunctionPass *llvm::createDumbSanitizerLegacyPassPass() {
+ return new DumbSanitizerLegacyPass();
+}
+
+Optional<InterestingMemoryAccess>
+DumbSanitizer::isInterestingMemoryAccess(Instruction *I) const {
+ InterestingMemoryAccess Access;
+
+ if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
+ if (!ClInstrumentReads)
+ return None;
+ Access.IsWrite = false;
+ Access.AccessTy = LI->getType();
+ Access.Alignment = LI->getAlignment();
+ Access.Addr = LI->getPointerOperand();
+ } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+ if (!ClInstrumentWrites)
+ return None;
+ Access.IsWrite = true;
+ Access.AccessTy = SI->getValueOperand()->getType();
+ Access.Alignment = SI->getAlignment();
+ Access.Addr = SI->getPointerOperand();
+ }
+
+ if (!Access.Addr)
+ return None;
+
+ // Do not instrument acesses from different address spaces; we cannot deal
+ // with them.
+ Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType());
+ if (PtrTy->getPointerAddressSpace() != 0)
+ return None;
+
+ const DataLayout &DL = I->getModule()->getDataLayout();
+ Access.TypeSize = DL.getTypeStoreSizeInBits(Access.AccessTy);
+ return Access;
+}
+
+void DumbSanitizer::instrumentMemoryAccess(Instruction *I, const DataLayout &DL,
+ InterestingMemoryAccess &Access) {
+ if (Access.IsWrite)
+ NumInstrumentedWrites++;
+ else
+ NumInstrumentedReads++;
+
+ IRBuilder<> IRB(I);
+ int Idx = getMemoryAccessFuncIndex(Access.TypeSize);
+ if (Idx < 0)
+ return;
+ FunctionCallee OnAccessFunc =
+ Access.IsWrite ? DbsanWrite[Idx] : DbsanRead[Idx];
+ IRB.CreateCall(OnAccessFunc,
+ IRB.CreatePointerCast(Access.Addr, IRB.getInt8PtrTy()));
+}
+
+int DumbSanitizer::getMemoryAccessFuncIndex(uint32_t TypeSize) {
+ if (TypeSize != 8 && TypeSize != 16 && TypeSize != 32 && TypeSize != 64 &&
+ TypeSize != 128) {
+ // Ignore all unusual sizes.
+ return -1;
+ }
+ size_t Idx = countTrailingZeros(TypeSize / 8);
+ assert(Idx < kNumberOfAccessSizes);
+ return Idx;
+}
+
+void DumbSanitizer::initializeCallbacks(Module &M) {
+ IRBuilder<> IRB(*C);
+ AttributeList Attr;
+ Attr = Attr.addFnAttribute(M.getContext(), Attribute::NoUnwind);
+
+ for (size_t i = 0; i < kNumberOfAccessSizes; ++i) {
+ const unsigned ByteSize = 1U << i;
+ std::string ByteSizeStr = utostr(ByteSize);
+ SmallString<32> ReadName("__dbsan_read" + ByteSizeStr);
+ DbsanRead[i] = M.getOrInsertFunction(ReadName, Attr, IRB.getVoidTy(),
+ IRB.getInt8PtrTy());
+
+ SmallString<32> WriteName("__dbsan_write" + ByteSizeStr);
+ DbsanWrite[i] = M.getOrInsertFunction(WriteName, Attr, IRB.getVoidTy(),
+ IRB.getInt8PtrTy());
+ }
+}
+
+bool DumbSanitizer::sanitizeFunction(Function &F) {
+ if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage)
+ return false;
+ if (F.getName().startswith("__dbsan_"))
+ return false;
+ if (F.getName() == kDbsanModuleCtorName)
+ return false;
+
+ bool FunctionModified = false;
+ LLVM_DEBUG(dbgs() << "dbsan instrumenting:\n" << F << "\n");
+
+ initializeCallbacks(*F.getParent());
+
+ SmallVector<Instruction *, 16> LoadsAndStores;
+ for (auto &BB : F) {
+ for (auto &Inst : BB) {
+ if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
+ LoadsAndStores.push_back(&Inst);
+ }
+ }
+
+ int NumInstrumented = 0;
+ for (auto *Inst : LoadsAndStores) {
+ Optional<InterestingMemoryAccess> Access = isInterestingMemoryAccess(Inst);
+ if (Access) {
+ instrumentMemoryAccess(Inst, F.getParent()->getDataLayout(), *Access);
+ NumInstrumented++;
+ }
+ }
+
+ if (NumInstrumented > 0)
+ FunctionModified = true;
+ LLVM_DEBUG(dbgs() << "dbsan done instrumenting: " << FunctionModified << " "
+ << F << "\n");
+ return FunctionModified;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment