26namespace win64_unwindinfo {
36#if defined(V8_OS_WIN_ARM64)
37 return !
v8_flags.win64_unwinding_info;
39 return !IsWindows8OrGreater() || !
v8_flags.win64_unwinding_info;
46 v8::UnhandledExceptionCallback unhandled_exception_callback) {
54extern "C" __declspec(dllexport)
int CRASH_HANDLER_FUNCTION_NAME(
58 EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord};
61 return ExceptionContinueSearch;
64#if defined(V8_OS_WIN_X64)
74 unsigned char CodeOffset;
75 unsigned char UnwindOp : 4;
76 unsigned char OpInfo : 4;
82 unsigned char Version : 3;
83 unsigned char Flags : 5;
84 unsigned char SizeOfProlog;
85 unsigned char CountOfCodes;
86 unsigned char FrameRegister : 4;
87 unsigned char FrameOffset : 4;
90static constexpr int kNumberOfUnwindCodes = 2;
91static constexpr int kMaxExceptionThunkSize = 12;
94 UNWIND_INFO unwind_info;
95 UNWIND_CODE unwind_codes[kNumberOfUnwindCodes];
98 static constexpr int kOpPushNonvol = 0;
99 static constexpr int kOpSetFPReg = 3;
101 unwind_info.Version = 1;
102 unwind_info.Flags = UNW_FLAG_EHANDLER;
103 unwind_info.SizeOfProlog = kRbpPrefixLength;
104 unwind_info.CountOfCodes = kRbpPrefixCodes;
105 unwind_info.FrameRegister = rbp.code();
106 unwind_info.FrameOffset = 0;
108 unwind_codes[0].CodeOffset = kRbpPrefixLength;
109 unwind_codes[0].UnwindOp = kOpSetFPReg;
110 unwind_codes[0].OpInfo = 0;
112 unwind_codes[1].CodeOffset = kPushRbpInstructionLength;
113 unwind_codes[1].UnwindOp = kOpPushNonvol;
114 unwind_codes[1].OpInfo = rbp.code();
118struct ExceptionHandlerUnwindData {
119 UNWIND_INFO unwind_info;
121 ExceptionHandlerUnwindData() {
122 unwind_info.Version = 1;
123 unwind_info.Flags = UNW_FLAG_EHANDLER;
124 unwind_info.SizeOfProlog = 0;
125 unwind_info.CountOfCodes = 0;
126 unwind_info.FrameRegister = 0;
127 unwind_info.FrameOffset = 0;
131struct CodeRangeUnwindingRecord {
133 uint32_t runtime_function_count;
134 V8UnwindData unwind_info;
135 uint32_t exception_handler;
136 uint8_t exception_thunk[kMaxExceptionThunkSize];
140struct ExceptionHandlerRecord {
141 uint32_t runtime_function_count;
143 ExceptionHandlerUnwindData unwind_info;
144 uint32_t exception_handler;
145 uint8_t exception_thunk[kMaxExceptionThunkSize];
150std::vector<uint8_t> GetUnwindInfoForBuiltinFunctions() {
152 return std::vector<uint8_t>(
153 reinterpret_cast<uint8_t*
>(&xdata),
154 reinterpret_cast<uint8_t*
>(&xdata) +
sizeof(xdata));
157template <
typename Record>
158void InitUnwindingRecord(Record*
record,
size_t code_size_in_bytes) {
163 record->runtime_function[0].BeginAddress = 0;
164 record->runtime_function[0].EndAddress =
165 static_cast<DWORD>(code_size_in_bytes);
166 record->runtime_function[0].UnwindData = offsetof(Record, unwind_info);
167 record->runtime_function_count = 1;
168 record->exception_handler = offsetof(Record, exception_thunk);
171 AccountingAllocator allocator;
173 options.record_reloc_info_for_serialization =
false;
176 masm.movq(rax,
reinterpret_cast<uint64_t
>(&CRASH_HANDLER_FUNCTION_NAME));
179 memcpy(&
record->exception_thunk[0], masm.buffer_start(),
180 masm.instruction_size());
183#elif defined(V8_OS_WIN_ARM64)
199typedef uint32_t UNWIND_CODE;
201constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0 = OpNop,
202 uint8_t code1 = OpNop,
203 uint8_t code2 = OpNop,
204 uint8_t code3 = OpNop) {
205 return static_cast<uint32_t
>(code0) | (
static_cast<uint32_t
>(code1) << 8) |
206 (
static_cast<uint32_t
>(code2) << 16) |
207 (
static_cast<uint32_t
>(code3) << 24);
214 uint32_t FunctionLength : 18;
215 uint32_t Version : 2;
218 uint32_t EpilogCount : 5;
219 uint32_t CodeWords : 5;
222static constexpr int kDefaultNumberOfUnwindCodeWords = 1;
223static constexpr int kMaxExceptionThunkSize = 16;
224static constexpr int kFunctionLengthShiftSize = 2;
225static constexpr int kFunctionLengthMask = (1 << kFunctionLengthShiftSize) - 1;
226static constexpr int kAllocStackShiftSize = 4;
227static constexpr int kAllocStackShiftMask = (1 << kAllocStackShiftSize) - 1;
230uint8_t MakeOpSaveFpLrX(
int pre_index_offset) {
235 constexpr int kShiftSize = 3;
236 constexpr int kShiftMask = (1 << kShiftSize) - 1;
237 DCHECK_EQ(pre_index_offset & kShiftMask, 0);
240 int encoded_value = (-pre_index_offset >> kShiftSize) - 1;
241 return OpSaveFpLrX | encoded_value;
245uint8_t MakeOpAllocS(
int stack_space) {
250 DCHECK_EQ(stack_space & kAllocStackShiftMask, 0);
251 return OpAllocS | (stack_space >> kAllocStackShiftSize);
255uint8_t MakeOpAddFpArgument(
int offset) {
259 constexpr int kShiftSize = 3;
260 constexpr int kShiftMask = (1 << kShiftSize) - 1;
263 int encoded_value =
offset >> kShiftSize;
266 return encoded_value;
269template <
int kNumberOfUnwindCodeWords = kDefaultNumberOfUnwindCodeWords>
271 UNWIND_INFO unwind_info;
272 UNWIND_CODE unwind_codes[kNumberOfUnwindCodeWords];
275 memset(&unwind_info, 0,
sizeof(UNWIND_INFO));
277 unwind_info.CodeWords = kNumberOfUnwindCodeWords;
290 static_assert(kNumberOfUnwindCodeWords >= 1);
291 unwind_codes[0] = Combine8BitUnwindCodes(
292 OpSetFp, MakeOpSaveFpLrX(-CommonFrameConstants::kCallerSPOffset),
296 for (
int i = 1;
i < kNumberOfUnwindCodeWords; ++
i) {
297 unwind_codes[
i] = Combine8BitUnwindCodes();
302struct CodeRangeUnwindingRecord {
304 uint32_t runtime_function_count;
305 V8UnwindData<> unwind_info;
306 uint32_t exception_handler;
312 V8UnwindData<> unwind_info1;
313 uint32_t exception_handler1;
314 uint8_t exception_thunk[kMaxExceptionThunkSize];
324FrameOffsets::FrameOffsets()
325 : fp_to_saved_caller_fp(CommonFrameConstants::kCallerFPOffset),
326 fp_to_caller_sp(CommonFrameConstants::kCallerSPOffset) {}
327bool FrameOffsets::IsDefault()
const {
329 return fp_to_saved_caller_fp == other.fp_to_saved_caller_fp &&
330 fp_to_caller_sp == other.fp_to_caller_sp;
333std::vector<uint8_t> GetUnwindInfoForBuiltinFunction(
334 uint32_t func_len, FrameOffsets fp_adjustment) {
336 DCHECK_EQ((func_len & kFunctionLengthMask), 0);
337 USE(kFunctionLengthMask);
340 constexpr int kMaxNumberOfUnwindCodeWords = 2;
342 V8UnwindData<kMaxNumberOfUnwindCodeWords> xdata;
345 xdata.unwind_info.FunctionLength = func_len >> kFunctionLengthShiftSize;
347 if (fp_adjustment.IsDefault()) {
349 static_assert(kDefaultNumberOfUnwindCodeWords <
350 kMaxNumberOfUnwindCodeWords);
351 xdata.unwind_info.CodeWords = kDefaultNumberOfUnwindCodeWords;
368 int pre_index_amount =
369 fp_adjustment.fp_to_saved_caller_fp - fp_adjustment.fp_to_caller_sp;
370 int stack_space = fp_adjustment.fp_to_saved_caller_fp;
371 int offset_from_stack_top = stack_space & kAllocStackShiftMask;
372 stack_space += offset_from_stack_top;
374 xdata.unwind_codes[0] = Combine8BitUnwindCodes(
375 OpAddFp, MakeOpAddFpArgument(offset_from_stack_top),
376 MakeOpAllocS(stack_space), MakeOpSaveFpLrX(pre_index_amount));
377 xdata.unwind_codes[1] = Combine8BitUnwindCodes(OpEnd);
380 return std::vector<uint8_t>(
381 reinterpret_cast<uint8_t*
>(&xdata),
382 reinterpret_cast<uint8_t*
>(
383 &xdata.unwind_codes[xdata.unwind_info.CodeWords]));
386template <
typename Record>
387void InitUnwindingRecord(Record*
record,
size_t code_size_in_bytes) {
395 constexpr uint32_t max_runtime_function_count =
static_cast<uint32_t
>(
397 kDefaultRuntimeFunctionCount);
399 uint32_t runtime_function_index = 0;
400 uint32_t current_unwind_start_address = 0;
401 int64_t remaining_size_in_bytes =
static_cast<int64_t
>(code_size_in_bytes);
408 while (remaining_size_in_bytes >= kMaxFunctionLength &&
409 runtime_function_index < max_runtime_function_count) {
410 record->runtime_function[runtime_function_index].BeginAddress =
411 current_unwind_start_address;
412 record->runtime_function[runtime_function_index].UnwindData =
413 static_cast<DWORD>(offsetof(Record, unwind_info));
415 runtime_function_index++;
416 current_unwind_start_address += kMaxFunctionLength;
417 remaining_size_in_bytes -= kMaxFunctionLength;
421 record->unwind_info.unwind_info.FunctionLength = kMaxFunctionLength >> 2;
423 if (remaining_size_in_bytes > 0 &&
424 runtime_function_index < max_runtime_function_count) {
427 record->unwind_info1.unwind_info.FunctionLength =
static_cast<uint32_t
>(
428 remaining_size_in_bytes >> kFunctionLengthShiftSize);
429 record->runtime_function[runtime_function_index].BeginAddress =
430 current_unwind_start_address;
431 record->runtime_function[runtime_function_index].UnwindData =
432 static_cast<DWORD>(offsetof(Record, unwind_info1));
434 remaining_size_in_bytes -= kMaxFunctionLength;
435 record->exception_handler1 = offsetof(Record, exception_thunk);
436 record->runtime_function_count = runtime_function_index + 1;
438 record->runtime_function_count = runtime_function_index;
446 record->exception_handler = offsetof(Record, exception_thunk);
449 AccountingAllocator allocator;
451 options.record_reloc_info_for_serialization =
false;
455 Operand(
reinterpret_cast<uint64_t
>(&CRASH_HANDLER_FUNCTION_NAME)));
458 memcpy(&
record->exception_thunk[0], masm.buffer_start(),
459 masm.instruction_size());
468 &::RtlAddGrowableFunctionTable) add_growable_function_table_func =
nullptr;
470 &::RtlDeleteGrowableFunctionTable) delete_growable_function_table_func =
473void LoadNtdllUnwindingFunctionsOnce() {
475 HMODULE ntdll_module =
476 LoadLibraryEx(
L"ntdll.dll",
nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
480 add_growable_function_table_func =
481 reinterpret_cast<decltype(&::RtlAddGrowableFunctionTable)
>(
482 ::GetProcAddress(ntdll_module,
"RtlAddGrowableFunctionTable"));
483 DCHECK_IMPLIES(IsWindows8OrGreater(), add_growable_function_table_func);
485 delete_growable_function_table_func =
486 reinterpret_cast<decltype(&::RtlDeleteGrowableFunctionTable)
>(
487 ::GetProcAddress(ntdll_module,
"RtlDeleteGrowableFunctionTable"));
488 DCHECK_IMPLIES(IsWindows8OrGreater(), delete_growable_function_table_func);
491void LoadNtdllUnwindingFunctions() {
493 &LoadNtdllUnwindingFunctionsOnce);
496bool AddGrowableFunctionTable(
PVOID* DynamicTable,
497 PRUNTIME_FUNCTION FunctionTable,
DWORD EntryCount,
500 DCHECK(::IsWindows8OrGreater());
502 LoadNtdllUnwindingFunctions();
505 *DynamicTable =
nullptr;
507 add_growable_function_table_func(DynamicTable, FunctionTable, EntryCount,
508 MaximumEntryCount, RangeBase, RangeEnd);
509 DCHECK((status == 0 && *DynamicTable !=
nullptr) ||
510 status == 0xC000009A);
511 return (status == 0);
514void DeleteGrowableFunctionTable(
PVOID dynamic_table) {
515 DCHECK(::IsWindows8OrGreater());
517 LoadNtdllUnwindingFunctions();
520 delete_growable_function_table_func(dynamic_table);
540#if defined(V8_OS_WIN_X64)
544 ExceptionHandlerRecord*
record =
new (
start) ExceptionHandlerRecord();
545 InitUnwindingRecord(
record, size_in_bytes);
547 CHECK(::RtlAddFunctionTable(
record->runtime_function,
548 kDefaultRuntimeFunctionCount,
549 reinterpret_cast<DWORD64
>(
start)));
553 CHECK(VirtualProtect(
start,
sizeof(ExceptionHandlerRecord),
554 PAGE_EXECUTE_READ, &old_protect));
558 CodeRangeUnwindingRecord*
record =
new (
start) CodeRangeUnwindingRecord();
559 InitUnwindingRecord(
record, size_in_bytes);
561 CHECK(AddGrowableFunctionTable(
563 record->runtime_function_count,
record->runtime_function_count,
564 reinterpret_cast<DWORD64
>(
start),
565 reinterpret_cast<DWORD64
>(
reinterpret_cast<uint8_t*
>(
start) +
570 CHECK(VirtualProtect(
start,
sizeof(CodeRangeUnwindingRecord),
571 PAGE_EXECUTE_READ, &old_protect));
579#if defined(V8_OS_WIN_X64)
583 ExceptionHandlerRecord*
record =
584 reinterpret_cast<ExceptionHandlerRecord*
>(
start);
585 CHECK(::RtlDeleteFunctionTable(
record->runtime_function));
589 CHECK(VirtualProtect(
start,
sizeof(ExceptionHandlerRecord),
590 PAGE_READWRITE, &old_protect));
594 CodeRangeUnwindingRecord*
record =
595 reinterpret_cast<CodeRangeUnwindingRecord*
>(
start);
596 if (
record->dynamic_table) {
597 DeleteGrowableFunctionTable(
record->dynamic_table);
602 CHECK(VirtualProtect(
start,
sizeof(CodeRangeUnwindingRecord),
603 PAGE_READWRITE, &old_protect));
607#if defined(V8_OS_WIN_X64)
609void XdataEncoder::onPushRbp() {
610 current_frame_code_offset_ =
611 assembler_.pc_offset() - kPushRbpInstructionLength;
614void XdataEncoder::onMovRbpRsp() {
615 if (current_frame_code_offset_ >= 0 &&
616 current_frame_code_offset_ ==
assembler_.pc_offset() - kRbpPrefixLength) {
617 fp_offsets_.push_back(current_frame_code_offset_);
621#elif defined(V8_OS_WIN_ARM64)
623void XdataEncoder::onSaveFpLr() {
624 current_frame_code_offset_ =
assembler_.pc_offset() - 4;
625 fp_offsets_.push_back(current_frame_code_offset_);
626 fp_adjustments_.push_back(current_frame_adjustment_);
627 current_frame_adjustment_ = FrameOffsets();
630void XdataEncoder::onFramePointerAdjustment(
int fp_to_saved_caller_fp,
631 int fp_to_caller_sp) {
632 current_frame_adjustment_.fp_to_saved_caller_fp = fp_to_saved_caller_fp;
633 current_frame_adjustment_.fp_to_caller_sp = fp_to_caller_sp;