diff --git a/compiler-rt/include/sanitizer/memprof_interface.h b/compiler-rt/include/sanitizer/memprof_interface.h index 4660a7818c92b..6d9b2a2394f41 100644 --- a/compiler-rt/include/sanitizer/memprof_interface.h +++ b/compiler-rt/include/sanitizer/memprof_interface.h @@ -47,9 +47,9 @@ void SANITIZER_CDECL __memprof_print_accumulated_stats(void); /// User-provided default option settings. /// -/// You can provide your own implementation of this function to return a string -/// containing MemProf runtime options (for example, -/// verbosity=1:print_stats=1). +/// You can set these options via the -memprof-runtime-default-options LLVM flag +/// or you can provide your own implementation of this function. See +/// memprof_flags.h for more info. /// /// \returns Default options string. const char *SANITIZER_CDECL __memprof_default_options(void); diff --git a/compiler-rt/lib/memprof/memprof_flags.cpp b/compiler-rt/lib/memprof/memprof_flags.cpp index b107ff8fa0a7c..95fde9d9672d6 100644 --- a/compiler-rt/lib/memprof/memprof_flags.cpp +++ b/compiler-rt/lib/memprof/memprof_flags.cpp @@ -89,5 +89,5 @@ void InitializeFlags() { } // namespace __memprof SANITIZER_INTERFACE_WEAK_DEF(const char *, __memprof_default_options, void) { - return ""; + return __memprof_default_options_str; } diff --git a/compiler-rt/lib/memprof/memprof_flags.h b/compiler-rt/lib/memprof/memprof_flags.h index 2f2b628653dc1..4dd395a6be94a 100644 --- a/compiler-rt/lib/memprof/memprof_flags.h +++ b/compiler-rt/lib/memprof/memprof_flags.h @@ -17,13 +17,15 @@ #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_internal_defs.h" -// MemProf flag values can be defined in four ways: -// 1) initialized with default values at startup. -// 2) overriden during compilation of MemProf runtime by providing -// compile definition MEMPROF_DEFAULT_OPTIONS. -// 3) overriden from string returned by user-specified function -// __memprof_default_options(). -// 4) overriden from env variable MEMPROF_OPTIONS. +// Default MemProf flags are defined in memprof_flags.inc and sancov_flags.inc. +// These values can be overridded in a number of ways, each option overrides the +// prior one: +// 1) by setting MEMPROF_DEFAULT_OPTIONS during the compilation of the MemProf +// runtime +// 2) by setting the LLVM flag -memprof-runtime-default-options during the +// compilation of your binary +// 3) by overriding the user-specified function __memprof_default_options() +// 4) by setting the environment variable MEMPROF_OPTIONS during runtime namespace __memprof { diff --git a/compiler-rt/lib/memprof/memprof_interface_internal.h b/compiler-rt/lib/memprof/memprof_interface_internal.h index 318bc41044056..7d3a937814a34 100644 --- a/compiler-rt/lib/memprof/memprof_interface_internal.h +++ b/compiler-rt/lib/memprof/memprof_interface_internal.h @@ -40,6 +40,9 @@ void __memprof_record_access_range(void const volatile *addr, uptr size); SANITIZER_INTERFACE_ATTRIBUTE void __memprof_print_accumulated_stats(); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE extern char + __memprof_default_options_str[1]; + SANITIZER_INTERFACE_ATTRIBUTE const char *__memprof_default_options(); diff --git a/compiler-rt/lib/memprof/memprof_rtl.cpp b/compiler-rt/lib/memprof/memprof_rtl.cpp index 2cc6c2df5a6fe..ef8884a7e56f4 100644 --- a/compiler-rt/lib/memprof/memprof_rtl.cpp +++ b/compiler-rt/lib/memprof/memprof_rtl.cpp @@ -27,6 +27,8 @@ #include +SANITIZER_WEAK_ATTRIBUTE char __memprof_default_options_str[1]; + uptr __memprof_shadow_memory_dynamic_address; // Global interface symbol. // Allow the user to specify a profile output file via the binary. diff --git a/compiler-rt/lib/memprof/weak_symbols.txt b/compiler-rt/lib/memprof/weak_symbols.txt index 271813612ab60..bfece89e2e157 100644 --- a/compiler-rt/lib/memprof/weak_symbols.txt +++ b/compiler-rt/lib/memprof/weak_symbols.txt @@ -1 +1 @@ -___memprof_default_options __memprof_profile_filename +___memprof_default_options_str ___memprof_default_options __memprof_profile_filename diff --git a/compiler-rt/test/memprof/TestCases/default_options.cpp b/compiler-rt/test/memprof/TestCases/default_options.cpp index 1b6b61fc048b6..4042a7df588b0 100644 --- a/compiler-rt/test/memprof/TestCases/default_options.cpp +++ b/compiler-rt/test/memprof/TestCases/default_options.cpp @@ -1,5 +1,8 @@ // RUN: %clangxx_memprof -O2 %s -o %t && %run %t 2>&1 | FileCheck %s +// Check that overriding __memprof_default_options() takes precedence over the LLVM flag +// RUN: %clangxx_memprof -O2 %s -o %t-flag -mllvm -memprof-runtime-default-options="verbosity=0 help=0" && %run %t-flag 2>&1 | FileCheck %s + const char *kMemProfDefaultOptions = "verbosity=1 help=1"; extern "C" const char *__memprof_default_options() { diff --git a/compiler-rt/test/memprof/TestCases/set_options.cpp b/compiler-rt/test/memprof/TestCases/set_options.cpp new file mode 100644 index 0000000000000..dddcfcf98c5c0 --- /dev/null +++ b/compiler-rt/test/memprof/TestCases/set_options.cpp @@ -0,0 +1,16 @@ +// RUN: %clangxx_memprof %s -o %t-default +// RUN: %run %t-default | FileCheck %s --check-prefix=DEFAULT + +// RUN: %clangxx_memprof %s -mllvm -memprof-runtime-default-options="print_text=true,log_path=stdout,atexit=false" -o %t +// RUN: %run %t | FileCheck %s + +#include +#include + +int main() { + printf("Options: \"%s\"\n", __memprof_default_options()); + return 0; +} + +// DEFAULT: Options: "" +// CHECK: Options: "print_text=true,log_path=stdout,atexit=false" diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp index 33a7a37fa28e6..ab7d3c7002991 100644 --- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp @@ -166,6 +166,11 @@ static cl::opt "context in this module's profiles"), cl::Hidden, cl::init(false)); +static cl::opt + MemprofRuntimeDefaultOptions("memprof-runtime-default-options", + cl::desc("The default memprof options"), + cl::Hidden, cl::init("")); + extern cl::opt MemProfReportHintedSizes; // Instrumentation statistics @@ -547,6 +552,20 @@ void createMemprofHistogramFlagVar(Module &M) { appendToCompilerUsed(M, MemprofHistogramFlag); } +void createMemprofDefaultOptionsVar(Module &M) { + Constant *OptionsConst = ConstantDataArray::getString( + M.getContext(), MemprofRuntimeDefaultOptions, /*AddNull=*/true); + GlobalVariable *OptionsVar = + new GlobalVariable(M, OptionsConst->getType(), /*isConstant=*/true, + GlobalValue::WeakAnyLinkage, OptionsConst, + "__memprof_default_options_str"); + Triple TT(M.getTargetTriple()); + if (TT.supportsCOMDAT()) { + OptionsVar->setLinkage(GlobalValue::ExternalLinkage); + OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName())); + } +} + bool ModuleMemProfiler::instrumentModule(Module &M) { // Create a module constructor. @@ -566,6 +585,8 @@ bool ModuleMemProfiler::instrumentModule(Module &M) { createMemprofHistogramFlagVar(M); + createMemprofDefaultOptionsVar(M); + return true; } diff --git a/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll new file mode 100644 index 0000000000000..8e82d524952dd --- /dev/null +++ b/llvm/test/Instrumentation/HeapProfiler/memprof-options.ll @@ -0,0 +1,11 @@ +; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S | FileCheck %s --check-prefixes=CHECK,EMPTY +; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes='function(memprof),memprof-module' -S -memprof-runtime-default-options="verbose=1" | FileCheck %s --check-prefixes=CHECK,VERBOSE + +define i32 @main() { +entry: + ret i32 0 +} + +; CHECK: $__memprof_default_options_str = comdat any +; EMPTY: @__memprof_default_options_str = constant [1 x i8] zeroinitializer, comdat +; VERBOSE: @__memprof_default_options_str = constant [10 x i8] c"verbose=1\00", comdat