aboutsummaryrefslogtreecommitdiff
path: root/lib/gwp_asan/optional
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gwp_asan/optional')
-rw-r--r--lib/gwp_asan/optional/backtrace.h23
-rw-r--r--lib/gwp_asan/optional/backtrace_linux_libc.cpp64
-rw-r--r--lib/gwp_asan/optional/backtrace_sanitizer_common.cpp69
-rw-r--r--lib/gwp_asan/optional/options_parser.cpp93
-rw-r--r--lib/gwp_asan/optional/options_parser.h31
5 files changed, 280 insertions, 0 deletions
diff --git a/lib/gwp_asan/optional/backtrace.h b/lib/gwp_asan/optional/backtrace.h
new file mode 100644
index 000000000000..2700970e5e8e
--- /dev/null
+++ b/lib/gwp_asan/optional/backtrace.h
@@ -0,0 +1,23 @@
+//===-- backtrace.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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef GWP_ASAN_OPTIONAL_BACKTRACE_H_
+#define GWP_ASAN_OPTIONAL_BACKTRACE_H_
+
+#include "gwp_asan/options.h"
+
+namespace gwp_asan {
+namespace options {
+// Functions to get the platform-specific and implementation-specific backtrace
+// and backtrace printing functions.
+Backtrace_t getBacktraceFunction();
+PrintBacktrace_t getPrintBacktraceFunction();
+} // namespace options
+} // namespace gwp_asan
+
+#endif // GWP_ASAN_OPTIONAL_BACKTRACE_H_
diff --git a/lib/gwp_asan/optional/backtrace_linux_libc.cpp b/lib/gwp_asan/optional/backtrace_linux_libc.cpp
new file mode 100644
index 000000000000..f20a3100927e
--- /dev/null
+++ b/lib/gwp_asan/optional/backtrace_linux_libc.cpp
@@ -0,0 +1,64 @@
+//===-- backtrace_linux_libc.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
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <execinfo.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gwp_asan/optional/backtrace.h"
+#include "gwp_asan/options.h"
+
+namespace {
+void Backtrace(uintptr_t *TraceBuffer, size_t Size) {
+ // Grab (what seems to be) one more trace than we need. TraceBuffer needs to
+ // be null-terminated, but we wish to remove the frame of this function call.
+ static_assert(sizeof(uintptr_t) == sizeof(void *), "uintptr_t is not void*");
+ int NumTraces =
+ backtrace(reinterpret_cast<void **>(TraceBuffer), Size);
+
+ // Now shift the entire trace one place to the left and null-terminate.
+ memmove(TraceBuffer, TraceBuffer + 1, NumTraces * sizeof(void *));
+ TraceBuffer[NumTraces - 1] = 0;
+}
+
+static void PrintBacktrace(uintptr_t *Trace,
+ gwp_asan::options::Printf_t Printf) {
+ size_t NumTraces = 0;
+ for (; Trace[NumTraces] != 0; ++NumTraces) {
+ }
+
+ if (NumTraces == 0) {
+ Printf(" <not found (does your allocator support backtracing?)>\n\n");
+ return;
+ }
+
+ char **BacktraceSymbols =
+ backtrace_symbols(reinterpret_cast<void **>(Trace), NumTraces);
+
+ for (size_t i = 0; i < NumTraces; ++i) {
+ if (!BacktraceSymbols)
+ Printf(" #%zu %p\n", i, Trace[i]);
+ else
+ Printf(" #%zu %s\n", i, BacktraceSymbols[i]);
+ }
+
+ Printf("\n");
+ if (BacktraceSymbols)
+ free(BacktraceSymbols);
+}
+} // anonymous namespace
+
+namespace gwp_asan {
+namespace options {
+Backtrace_t getBacktraceFunction() { return Backtrace; }
+PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; }
+} // namespace options
+} // namespace gwp_asan
diff --git a/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp b/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp
new file mode 100644
index 000000000000..7d17eec0da2f
--- /dev/null
+++ b/lib/gwp_asan/optional/backtrace_sanitizer_common.cpp
@@ -0,0 +1,69 @@
+//===-- backtrace_sanitizer_common.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
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "gwp_asan/optional/backtrace.h"
+#include "gwp_asan/options.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
+ void *context,
+ bool request_fast,
+ u32 max_depth) {
+ if (!StackTrace::WillUseFastUnwind(request_fast)) {
+ return Unwind(max_depth, pc, bp, context, 0, 0, request_fast);
+ }
+ Unwind(max_depth, pc, 0, context, 0, 0, false);
+}
+
+namespace {
+void Backtrace(uintptr_t *TraceBuffer, size_t Size) {
+ __sanitizer::BufferedStackTrace Trace;
+ Trace.Reset();
+ if (Size > __sanitizer::kStackTraceMax)
+ Size = __sanitizer::kStackTraceMax;
+
+ Trace.Unwind((__sanitizer::uptr)__builtin_return_address(0),
+ (__sanitizer::uptr)__builtin_frame_address(0),
+ /* ucontext */ nullptr,
+ /* fast unwind */ true, Size - 1);
+
+ memcpy(TraceBuffer, Trace.trace, Trace.size * sizeof(uintptr_t));
+ TraceBuffer[Trace.size] = 0;
+}
+
+static void PrintBacktrace(uintptr_t *Trace,
+ gwp_asan::options::Printf_t Printf) {
+ __sanitizer::StackTrace StackTrace;
+ StackTrace.trace = reinterpret_cast<__sanitizer::uptr *>(Trace);
+
+ for (StackTrace.size = 0; StackTrace.size < __sanitizer::kStackTraceMax;
+ ++StackTrace.size) {
+ if (Trace[StackTrace.size] == 0)
+ break;
+ }
+
+ if (StackTrace.size == 0) {
+ Printf(" <unknown (does your allocator support backtracing?)>\n\n");
+ return;
+ }
+
+ StackTrace.Print();
+}
+} // anonymous namespace
+
+namespace gwp_asan {
+namespace options {
+Backtrace_t getBacktraceFunction() { return Backtrace; }
+PrintBacktrace_t getPrintBacktraceFunction() { return PrintBacktrace; }
+} // namespace options
+} // namespace gwp_asan
diff --git a/lib/gwp_asan/optional/options_parser.cpp b/lib/gwp_asan/optional/options_parser.cpp
new file mode 100644
index 000000000000..6c2167288d6c
--- /dev/null
+++ b/lib/gwp_asan/optional/options_parser.cpp
@@ -0,0 +1,93 @@
+//===-- options_parser.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "gwp_asan/optional/options_parser.h"
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gwp_asan/options.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
+
+namespace gwp_asan {
+namespace options {
+namespace {
+void registerGwpAsanFlags(__sanitizer::FlagParser *parser, Options *o) {
+#define GWP_ASAN_OPTION(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &o->Name);
+#include "gwp_asan/options.inc"
+#undef GWP_ASAN_OPTION
+}
+
+const char *getCompileDefinitionGwpAsanDefaultOptions() {
+#ifdef GWP_ASAN_DEFAULT_OPTIONS
+ return SANITIZER_STRINGIFY(GWP_ASAN_DEFAULT_OPTIONS);
+#else
+ return "";
+#endif
+}
+
+const char *getGwpAsanDefaultOptions() {
+ return (__gwp_asan_default_options) ? __gwp_asan_default_options() : "";
+}
+
+Options *getOptionsInternal() {
+ static Options GwpAsanFlags;
+ return &GwpAsanFlags;
+}
+} // anonymous namespace
+
+void initOptions() {
+ __sanitizer::SetCommonFlagsDefaults();
+
+ Options *o = getOptionsInternal();
+ o->setDefaults();
+
+ __sanitizer::FlagParser Parser;
+ registerGwpAsanFlags(&Parser, o);
+
+ // Override from compile definition.
+ Parser.ParseString(getCompileDefinitionGwpAsanDefaultOptions());
+
+ // Override from user-specified string.
+ Parser.ParseString(getGwpAsanDefaultOptions());
+
+ // Override from environment.
+ Parser.ParseString(__sanitizer::GetEnv("GWP_ASAN_OPTIONS"));
+
+ __sanitizer::InitializeCommonFlags();
+ if (__sanitizer::Verbosity())
+ __sanitizer::ReportUnrecognizedFlags();
+
+ if (!o->Enabled)
+ return;
+
+ // Sanity checks for the parameters.
+ if (o->MaxSimultaneousAllocations <= 0) {
+ __sanitizer::Printf("GWP-ASan ERROR: MaxSimultaneousAllocations must be > "
+ "0 when GWP-ASan is enabled.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (o->SampleRate < 1) {
+ __sanitizer::Printf(
+ "GWP-ASan ERROR: SampleRate must be > 0 when GWP-ASan is enabled.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ o->Printf = __sanitizer::Printf;
+}
+
+Options &getOptions() { return *getOptionsInternal(); }
+
+} // namespace options
+} // namespace gwp_asan
diff --git a/lib/gwp_asan/optional/options_parser.h b/lib/gwp_asan/optional/options_parser.h
new file mode 100644
index 000000000000..7a6bfaf0ce3e
--- /dev/null
+++ b/lib/gwp_asan/optional/options_parser.h
@@ -0,0 +1,31 @@
+//===-- options_parser.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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_
+#define GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_
+
+#include "gwp_asan/optional/backtrace.h"
+#include "gwp_asan/options.h"
+#include "sanitizer_common/sanitizer_common.h"
+
+namespace gwp_asan {
+namespace options {
+// Parse the options from the GWP_ASAN_FLAGS environment variable.
+void initOptions();
+// Returns the initialised options. Call initOptions() prior to calling this
+// function.
+Options &getOptions();
+} // namespace options
+} // namespace gwp_asan
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *
+__gwp_asan_default_options();
+}
+
+#endif // GWP_ASAN_OPTIONAL_OPTIONS_PARSER_H_