brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.1 KiB · 66f74ff Raw
128 lines · cpp
1//===--- RunOnNewStack.cpp - Crash Recovery -------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/ProgramStack.h"10#include "llvm/Config/config.h"11#include "llvm/Support/Compiler.h"12 13#ifdef LLVM_ON_UNIX14# include <sys/resource.h> // for getrlimit15#endif16 17#ifdef _MSC_VER18# include <intrin.h>  // for _AddressOfReturnAddress19#endif20 21#ifndef LLVM_HAS_SPLIT_STACKS22# include "llvm/Support/thread.h"23#endif24 25using namespace llvm;26 27uintptr_t llvm::getStackPointer() {28#if __GNUC__ || __has_builtin(__builtin_frame_address)29  return (uintptr_t)__builtin_frame_address(0);30#elif defined(_MSC_VER)31  return (uintptr_t)_AddressOfReturnAddress();32#else33  volatile char CharOnStack = 0;34  // The volatile store here is intended to escape the local variable, to35  // prevent the compiler from optimizing CharOnStack into anything other36  // than a char on the stack.37  //38  // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19.39  char *volatile Ptr = &CharOnStack;40  return (uintptr_t)Ptr;41#endif42}43 44unsigned llvm::getDefaultStackSize() {45#ifdef LLVM_ON_UNIX46  rlimit RL;47  getrlimit(RLIMIT_STACK, &RL);48  return RL.rlim_cur;49#else50  // Clang recursively parses, instantiates templates, and evaluates constant51  // expressions. We've found 8MiB to be a reasonable stack size given the way52  // Clang works and the way C++ is commonly written.53  return 8 << 20;54#endif55}56 57// Not an anonymous namespace to avoid warning about undefined local function.58namespace llvm {59#ifdef LLVM_HAS_SPLIT_STACKS_AARCH6460void runOnNewStackImpl(void *Stack, void (*Fn)(void *), void *Ctx) __asm__(61    "_ZN4llvm17runOnNewStackImplEPvPFvS0_ES0_");62 63// This can't use naked functions because there is no way to know if cfi64// directives are being emitted or not.65//66// When adding new platforms it may be better to move to a .S file with macros67// for dealing with platform differences.68__asm__ (69    ".globl  _ZN4llvm17runOnNewStackImplEPvPFvS0_ES0_\n\t"70    ".p2align  2\n\t"71    "_ZN4llvm17runOnNewStackImplEPvPFvS0_ES0_:\n\t"72    ".cfi_startproc\n\t"73    "mov       x16, sp\n\t"74    "sub       x0, x0, #0x20\n\t"            // subtract space from stack75    "stp       xzr, x16, [x0, #0x00]\n\t"    // save old sp76    "stp       x29, x30, [x0, #0x10]\n\t"    // save fp, lr77    "mov       sp, x0\n\t"                   // switch to new stack78    "add       x29, x0, #0x10\n\t"           // switch to new frame79    ".cfi_def_cfa w29, 16\n\t"80    ".cfi_offset w30, -8\n\t"                // lr81    ".cfi_offset w29, -16\n\t"               // fp82 83    "mov       x0, x2\n\t"                   // Ctx is the only argument84    "blr       x1\n\t"                       // call Fn85 86    "ldp       x29, x30, [sp, #0x10]\n\t"    // restore fp, lr87    "ldp       xzr, x16, [sp, #0x00]\n\t"    // load old sp88    "mov       sp, x16\n\t"89    "ret\n\t"90    ".cfi_endproc"91);92#endif93} // namespace llvm94 95namespace {96#ifdef LLVM_HAS_SPLIT_STACKS97void callback(void *Ctx) {98  (*reinterpret_cast<function_ref<void()> *>(Ctx))();99}100#endif101} // namespace102 103#ifdef LLVM_HAS_SPLIT_STACKS104void llvm::runOnNewStack(unsigned StackSize, function_ref<void()> Fn) {105  if (StackSize == 0)106    StackSize = getDefaultStackSize();107 108  // We use malloc here instead of mmap because:109  //   - it's simpler,110  //   - many malloc implementations will reuse the allocation in cases where111  //     we're bouncing accross the edge of a stack boundry, and112  //   - many malloc implemenations will already provide guard pages for113  //     allocations this large.114  void *Stack = malloc(StackSize);115  void *BottomOfStack = (char *)Stack + StackSize;116 117  runOnNewStackImpl(BottomOfStack, callback, &Fn);118 119  free(Stack);120}121#else122void llvm::runOnNewStack(unsigned StackSize, function_ref<void()> Fn) {123  llvm::thread Thread(124      StackSize == 0 ? std::nullopt : std::optional<unsigned>(StackSize), Fn);125  Thread.join();126}127#endif128