aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/ProgramStack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/ProgramStack.cpp')
-rw-r--r--llvm/lib/Support/ProgramStack.cpp114
1 files changed, 114 insertions, 0 deletions
diff --git a/llvm/lib/Support/ProgramStack.cpp b/llvm/lib/Support/ProgramStack.cpp
new file mode 100644
index 0000000..9e5a546
--- /dev/null
+++ b/llvm/lib/Support/ProgramStack.cpp
@@ -0,0 +1,114 @@
+//===--- RunOnNewStack.cpp - Crash Recovery -------------------------------===//
+//
+// 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 "llvm/Support/ProgramStack.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Compiler.h"
+
+#ifdef LLVM_ON_UNIX
+# include <sys/resource.h> // for getrlimit
+#endif
+
+#ifdef _MSC_VER
+# include <intrin.h> // for _AddressOfReturnAddress
+#endif
+
+#ifndef LLVM_HAS_SPLIT_STACKS
+# include "llvm/Support/thread.h"
+#endif
+
+using namespace llvm;
+
+uintptr_t llvm::getStackPointer() {
+#if __GNUC__ || __has_builtin(__builtin_frame_address)
+ return (uintptr_t)__builtin_frame_address(0);
+#elif defined(_MSC_VER)
+ return (uintptr_t)_AddressOfReturnAddress();
+#else
+ volatile char CharOnStack = 0;
+ // The volatile store here is intended to escape the local variable, to
+ // prevent the compiler from optimizing CharOnStack into anything other
+ // than a char on the stack.
+ //
+ // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19.
+ char *volatile Ptr = &CharOnStack;
+ return (uintptr_t)Ptr;
+#endif
+}
+
+unsigned llvm::getDefaultStackSize() {
+#ifdef LLVM_ON_UNIX
+ rlimit RL;
+ getrlimit(RLIMIT_STACK, &RL);
+ return RL.rlim_cur;
+#else
+ // Clang recursively parses, instantiates templates, and evaluates constant
+ // expressions. We've found 8MiB to be a reasonable stack size given the way
+ // Clang works and the way C++ is commonly written.
+ return 8 << 20;
+#endif
+}
+
+namespace {
+#ifdef LLVM_HAS_SPLIT_STACKS_AARCH64
+[[gnu::naked]] void runOnNewStackImpl(void *Stack, void (*Fn)(void *),
+ void *Ctx) {
+ __asm__ volatile(
+ "mov x16, sp\n\t"
+ "sub x0, x0, #0x20\n\t" // subtract space from stack
+ "stp xzr, x16, [x0, #0x00]\n\t" // save old sp
+ "stp x29, x30, [x0, #0x10]\n\t" // save fp, lr
+ "mov sp, x0\n\t" // switch to new stack
+ "add x29, x0, #0x10\n\t" // switch to new frame
+ ".cfi_def_cfa w29, 16\n\t"
+ ".cfi_offset w30, -8\n\t" // lr
+ ".cfi_offset w29, -16\n\t" // fp
+
+ "mov x0, x2\n\t" // Ctx is the only argument
+ "blr x1\n\t" // call Fn
+
+ "ldp x29, x30, [sp, #0x10]\n\t" // restore fp, lr
+ "ldp xzr, x16, [sp, #0x00]\n\t" // load old sp
+ "mov sp, x16\n\t"
+ "ret"
+ );
+}
+#endif
+
+#ifdef LLVM_HAS_SPLIT_STACKS
+void callback(void *Ctx) {
+ (*reinterpret_cast<function_ref<void()> *>(Ctx))();
+}
+#endif
+} // namespace
+
+#ifdef LLVM_HAS_SPLIT_STACKS
+void llvm::runOnNewStack(unsigned StackSize, function_ref<void()> Fn) {
+ if (StackSize == 0)
+ StackSize = getDefaultStackSize();
+
+ // We use malloc here instead of mmap because:
+ // - it's simpler,
+ // - many malloc implementations will reuse the allocation in cases where
+ // we're bouncing accross the edge of a stack boundry, and
+ // - many malloc implemenations will already provide guard pages for
+ // allocations this large.
+ void *Stack = malloc(StackSize);
+ void *BottomOfStack = (char *)Stack + StackSize;
+
+ runOnNewStackImpl(BottomOfStack, callback, &Fn);
+
+ free(Stack);
+}
+#else
+void llvm::runOnNewStack(unsigned StackSize, function_ref<void()> Fn) {
+ llvm::thread Thread(
+ StackSize == 0 ? std::nullopt : std::optional<unsigned>(StackSize), Fn);
+ Thread.join();
+}
+#endif