unwinding-info-win64.h 5.73 KB
Newer Older
1 2 3 4
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef V8_DIAGNOSTICS_UNWINDING_INFO_WIN64_H_
#define V8_DIAGNOSTICS_UNWINDING_INFO_WIN64_H_
7

8
#include "include/v8.h"
9
#include "include/v8config.h"
10
#include "src/common/globals.h"
11

12
#if defined(V8_OS_WIN64)
13 14 15 16 17 18 19 20 21 22 23
#include "src/base/win32-headers.h"

namespace v8 {
namespace internal {

namespace win64_unwindinfo {

#define CRASH_HANDLER_FUNCTION_NAME CrashForExceptionInNonABICompliantCodeRange
#define CRASH_HANDLER_FUNCTION_NAME_STRING \
  "CrashForExceptionInNonABICompliantCodeRange"

24
static const int kOSPageSize = 4096;
25 26 27 28 29 30 31 32 33 34

/**
 * Returns true if V8 is configured to emit unwinding data for embedded in the
 * pdata/xdata sections of the executable. Currently, this happens when V8 is
 * built with "v8_win64_unwinding_info = true".
 */
bool CanEmitUnwindInfoForBuiltins();

/**
 * Returns true if V8 if we can register unwinding data for the whole code range
35
 * of an isolate or Wasm module. The first page of the code range is reserved
36 37 38 39 40 41 42 43 44 45 46 47 48
 * and writable, to be used to store unwind data, as documented in:
 * https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
 * In jitless mode V8 does not allocate any executable memory itself so the only
 * non-abi-compliant code range is in the embedded blob.
 */
bool CanRegisterUnwindInfoForNonABICompliantCodeRange();

/**
 * Registers a custom exception handler for exceptions in V8-generated code.
 */
void SetUnhandledExceptionCallback(
    v8::UnhandledExceptionCallback unhandled_exception_callback);

49 50 51
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes);
void UnregisterNonABICompliantCodeRange(void* start);

52
/**
53 54
 * Default count of RUNTIME_FUNCTION needed. For Windows X64, 1 RUNTIME_FUNCTION
 * covers 4GB range which is sufficient to cover the whole code range of an
55
 * isolate or Wasm module. For Windows ARM64, 1 RUNTIME_FUNCTION covers
56
 * kMaxFunctionLength bytes so multiple RUNTIME_FUNCTION structs could be needed
57
 * to cover the whole code range of an isolate or Wasm module. The extra
58 59 60 61 62 63 64 65 66 67 68 69 70 71
 * RUNTIME_FUNCTIONs are assumed following the first one in the reserved page.
 */
static const uint32_t kDefaultRuntimeFunctionCount = 1;

#if defined(V8_OS_WIN_X64)

static const int kPushRbpInstructionLength = 1;
static const int kMovRbpRspInstructionLength = 3;
static const int kRbpPrefixCodes = 2;
static const int kRbpPrefixLength =
    kPushRbpInstructionLength + kMovRbpRspInstructionLength;

/**
 * Returns a vector of bytes that contains the Win X64 unwind data used for all
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
 * V8 builtin functions.
 */
std::vector<uint8_t> GetUnwindInfoForBuiltinFunctions();

class BuiltinUnwindInfo {
 public:
  BuiltinUnwindInfo() : is_leaf_function_(true) {}
  explicit BuiltinUnwindInfo(const std::vector<int>& fp_offsets)
      : is_leaf_function_(false), fp_offsets_(fp_offsets) {}

  bool is_leaf_function() const { return is_leaf_function_; }
  const std::vector<int>& fp_offsets() const { return fp_offsets_; }

 private:
  bool is_leaf_function_;
  std::vector<int> fp_offsets_;
};

class XdataEncoder {
 public:
  explicit XdataEncoder(const Assembler& assembler)
93
      : assembler_(assembler), current_frame_code_offset_(-1) {}
94 95 96 97 98 99 100 101 102 103 104

  void onPushRbp();
  void onMovRbpRsp();

  BuiltinUnwindInfo unwinding_info() const {
    return BuiltinUnwindInfo(fp_offsets_);
  }

 private:
  const Assembler& assembler_;
  std::vector<int> fp_offsets_;
105
  int current_frame_code_offset_;
106 107
};

108
#elif defined(V8_OS_WIN_ARM64)
109

110 111 112 113 114 115 116
/**
 * Base on below doc, unwind record has 18 bits (unsigned) to encode function
 * length, besides 2 LSB which are always 0.
 * https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records
 */
static const int kMaxFunctionLength = ((1 << 18) - 1) << 2;

117 118 119 120 121 122 123
struct FrameOffsets {
  FrameOffsets();
  bool IsDefault() const;
  int fp_to_saved_caller_fp;
  int fp_to_caller_sp;
};

124 125 126 127 128 129 130 131 132
/**
 * Returns a vector of bytes that contains the Win ARM64 unwind data used for
 * all V8 builtin functions.
 *
 * func_len: length in bytes of current function/region to unwind.
 * fp_adjustment: offset of the saved caller's fp based on fp in current frame.
 *                this is necessary to encode unwind data for Windows stack
 *                unwinder to find correct caller's fp.
 */
133 134
std::vector<uint8_t> GetUnwindInfoForBuiltinFunction(
    uint32_t func_len, FrameOffsets fp_adjustment);
135 136 137 138
class BuiltinUnwindInfo {
 public:
  BuiltinUnwindInfo() : is_leaf_function_(true) {}
  explicit BuiltinUnwindInfo(const std::vector<int>& fp_offsets,
139
                             const std::vector<FrameOffsets>& fp_adjustments)
140 141 142 143
      : is_leaf_function_(false),
        fp_offsets_(fp_offsets),
        fp_adjustments_(fp_adjustments) {}

144 145 146
  const std::vector<FrameOffsets>& fp_adjustments() const {
    return fp_adjustments_;
  }
147 148 149 150 151 152 153

  bool is_leaf_function() const { return is_leaf_function_; }
  const std::vector<int>& fp_offsets() const { return fp_offsets_; }

 private:
  bool is_leaf_function_;
  std::vector<int> fp_offsets_;
154
  std::vector<FrameOffsets> fp_adjustments_;
155 156 157 158 159
};

class XdataEncoder {
 public:
  explicit XdataEncoder(const Assembler& assembler)
160
      : assembler_(assembler), current_frame_code_offset_(-1) {}
161 162

  void onSaveFpLr();
163
  void onFramePointerAdjustment(int fp_to_saved_caller_fp, int fp_to_caller_sp);
164 165 166 167 168 169 170 171 172

  BuiltinUnwindInfo unwinding_info() const {
    return BuiltinUnwindInfo(fp_offsets_, fp_adjustments_);
  }

 private:
  const Assembler& assembler_;
  std::vector<int> fp_offsets_;
  int current_frame_code_offset_;
173 174
  FrameOffsets current_frame_adjustment_;
  std::vector<FrameOffsets> fp_adjustments_;
175 176 177 178 179
};

#endif

}  // namespace win64_unwindinfo
180 181 182
}  // namespace internal
}  // namespace v8

183
#endif  // V8_OS_WIN64
184

185
#endif  // V8_DIAGNOSTICS_UNWINDING_INFO_WIN64_H_