From 57621d08c59b1011d8e7813360a9e904b5440f77 Mon Sep 17 00:00:00 2001 From: Richard Townsend Date: Tue, 23 Jul 2019 15:15:28 +0100 Subject: [PATCH 1/8] feat: cherry-pick V8 unwinding support This commit backports [1] (originally written by @ThomsonTan) into V8 7.6. With this patch in place, calls made from JS into the atom core which crash electron.exe will now generate crash dumps on Windows on Arm rather than silently dying. [1] https://chromium-review.googlesource.com/c/v8/v8/+/1701133/11 --- patches/common/v8/.patches | 1 + ...v8_frames_correctly_on_windows_arm64.patch | 1528 +++++++++++++++++ 2 files changed, 1529 insertions(+) create mode 100644 patches/common/v8/unwind_v8_frames_correctly_on_windows_arm64.patch diff --git a/patches/common/v8/.patches b/patches/common/v8/.patches index 13d69fdada3c6..6426e8b225a2a 100644 --- a/patches/common/v8/.patches +++ b/patches/common/v8/.patches @@ -6,3 +6,4 @@ dcheck.patch export_symbols_needed_for_windows_build.patch workaround_an_undefined_symbol_error.patch do_not_export_private_v8_symbols_on_windows.patch +unwind_v8_frames_correctly_on_windows_arm64.patch diff --git a/patches/common/v8/unwind_v8_frames_correctly_on_windows_arm64.patch b/patches/common/v8/unwind_v8_frames_correctly_on_windows_arm64.patch new file mode 100644 index 0000000000000..8480dc2ed028f --- /dev/null +++ b/patches/common/v8/unwind_v8_frames_correctly_on_windows_arm64.patch @@ -0,0 +1,1528 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tom Tan +Date: Tue, 23 Jul 2019 00:02:23 -0700 +Subject: Unwind V8 frames correctly on Windows ARM64 + +On Windows ARM64, OS stack walking does not work because the V8 ARM64 backend +doesn't emit unwinding info and also because it doesn't emit ABI compliant +stack frames. This was fixed for Windows X64 (https://crrev.com/c/1469329) and +documented below: + +https://docs.google.com/document/d/1-wf50jFlii0c_Pr52lm2ZU-49m220nhYMrHDi3vXnh0 + +This problem can be fixed similarly for Windows ARM64 by observing that V8 +frames usually all have the same prolog which maintains a chain via frame +pointer (fp or x29 register). + +stp fp, lr, [sp, ...] + +One exception is JSEntry which stops fp pointer chain and needs to be handled +specially. + +So it is possible to define XDATA with UNWIND_CODE which specify how Windows +should walk through V8 dynamic frames. The same as X64, since V8 Code objects +are all allocated in the same code-range for an Isolate, it is possible to +register at most 2 XDATA and a group of PDATA entries to cover stack walking +for all the code generated inside that code-range. This is more than 1 +PDATA/XDATA because according to the Windows ARM64 exeption handling document, +1 PDATA can cover less than 1MB code range (see below doc). + +https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling + +This PR implements stackwalk for Windows ARM64 to be on par with X64, including +embedded builtins, jitted code and wasm jitted code, but not including register +handler for handling exception only, because there is no backward compatibility +to maintain for Windows ARM64 which was released since 1709 windows build. + +Bug: chromium:893460 +Change-Id: Ic74cbdad8af5cf342185030a4c53796f12ea5429 + +diff --git a/BUILD.gn b/BUILD.gn +index 071a85c3f57ae92dcf90d47a13299e43f81753ec..d3cc60935541d080234ebc30b231904a48e68862 100644 +--- a/BUILD.gn ++++ b/BUILD.gn +@@ -91,7 +91,7 @@ declare_args() { + # Enable embedded builtins. + v8_enable_embedded_builtins = true + +- # Enable the registration of unwinding info for Windows/x64. ++ # Enable the registration of unwinding info for Windows x64 and ARM64. + v8_win64_unwinding_info = true + + # Enable code comments for builtins in the snapshot (impacts performance). +@@ -3131,6 +3131,12 @@ v8_source_set("v8_base_without_compiler") { + "src/regexp/arm64/regexp-macro-assembler-arm64.h", + "src/wasm/baseline/arm64/liftoff-assembler-arm64.h", + ] ++ if (is_win) { ++ sources += [ ++ "src/diagnostics/unwinding-info-win64.cc", ++ "src/diagnostics/unwinding-info-win64.h", ++ ] ++ } + jumbo_excluded_sources += [ + # TODO(mostynb@vewd.com): fix this code so it doesn't need + # to be excluded, see the comments inside. +diff --git a/src/api/api.cc b/src/api/api.cc +index 6117189ad11a189e03c4db1307d919b818751b18..41a7fefec2c1ec6af55a81f2298ab6a43b76b4bb 100644 +--- a/src/api/api.cc ++++ b/src/api/api.cc +@@ -121,9 +121,9 @@ + #include + #include "include/v8-wasm-trap-handler-win.h" + #include "src/trap-handler/handler-inside-win.h" +-#if V8_TARGET_ARCH_X64 ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif // V8_TARGET_ARCH_X64 ++#endif // V8_OS_WIN64 + #endif // V8_OS_WIN + + namespace v8 { +@@ -5609,14 +5609,14 @@ bool V8::EnableWebAssemblyTrapHandler(bool use_v8_signal_handler) { + #if defined(V8_OS_WIN) + void V8::SetUnhandledExceptionCallback( + UnhandledExceptionCallback unhandled_exception_callback) { +-#if defined(V8_TARGET_ARCH_X64) ++#if defined(V8_OS_WIN64) + v8::internal::win64_unwindinfo::SetUnhandledExceptionCallback( + unhandled_exception_callback); + #else +- // Not implemented on ARM64. +-#endif ++ // Not implemented. ++#endif // V8_OS_WIN64 + } +-#endif ++#endif // V8_OS_WIN + + void v8::V8::SetEntropySource(EntropySource entropy_source) { + base::RandomNumberGenerator::SetEntropySource(entropy_source); +diff --git a/src/builtins/arm64/builtins-arm64.cc b/src/builtins/arm64/builtins-arm64.cc +index f81a1955eeb474c527f25f9e59edb0522e81824b..560e53a61c65086744b817a3fb5f32ee1f82dbd7 100644 +--- a/src/builtins/arm64/builtins-arm64.cc ++++ b/src/builtins/arm64/builtins-arm64.cc +@@ -24,6 +24,10 @@ + #include "src/runtime/runtime.h" + #include "src/wasm/wasm-objects.h" + ++#if defined(V8_OS_WIN) ++#include "src/diagnostics/unwinding-info-win64.h" ++#endif // V8_OS_WIN ++ + namespace v8 { + namespace internal { + +@@ -623,6 +627,23 @@ void Generate_JSEntryVariant(MacroAssembler* masm, StackFrame::Type type, + // will have no effect on the model or real hardware. + __ EnableInstrumentation(); + ++#if defined(V8_OS_WIN) ++ // Windows ARM64 relies on frame pointer (fp/x29 which are aliases to each ++ // other) chain to do stack unwinding, but JSEntry breaks that by setting fp ++ // to point to bad_frame_pointer below. To fix unwind information for this ++ // case, JSEntry registers the offset (from current fp to the caller's fp ++ // saved by PushCalleeSavedRegisters on stack) to xdata_encoder which then ++ // emits the offset value as part of result unwind data accordingly. The ++ // current offset is kFramePointerOffset which includes bad_frame_pointer ++ // saved below plus kFramePointerOffsetInPushCalleeSavedRegisters. ++ const int kFramePointerOffset = ++ kFramePointerOffsetInPushCalleeSavedRegisters + kSystemPointerSize; ++ win64_unwindinfo::XdataEncoder* xdata_encoder = masm->GetXdataEncoder(); ++ if (xdata_encoder) { ++ xdata_encoder->onFramePointerAdjustment(kFramePointerOffset); ++ } ++#endif ++ + __ PushCalleeSavedRegisters(); + + // Set up the reserved register for 0.0. +diff --git a/src/builtins/setup-builtins-internal.cc b/src/builtins/setup-builtins-internal.cc +index 7b4a068300e20f56a1491a494ed8978dbb95398a..39cbf15b6504ce380d165b56ca20e52460d65b23 100644 +--- a/src/builtins/setup-builtins-internal.cc ++++ b/src/builtins/setup-builtins-internal.cc +@@ -119,9 +119,9 @@ Code BuildWithMacroAssembler(Isolate* isolate, int32_t builtin_index, + .set_self_reference(masm.CodeObject()) + .set_builtin_index(builtin_index) + .Build(); +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + isolate->SetBuiltinUnwindData(builtin_index, masm.GetUnwindInfo()); +-#endif ++#endif // V8_OS_WIN64 + return *code; + } + +diff --git a/src/codegen/arm64/assembler-arm64.cc b/src/codegen/arm64/assembler-arm64.cc +index 53da75760ba31bed3e3cf19397474b353bc83fdf..d94370f5d7d6456a21f681bd81afa54e06863ce3 100644 +--- a/src/codegen/arm64/assembler-arm64.cc ++++ b/src/codegen/arm64/assembler-arm64.cc +@@ -520,6 +520,12 @@ Assembler::Assembler(const AssemblerOptions& options, + const_pool_blocked_nesting_ = 0; + veneer_pool_blocked_nesting_ = 0; + Reset(); ++ ++#if defined(V8_OS_WIN) ++ if (options.collect_win64_unwind_info) { ++ xdata_encoder_ = std::make_unique(*this); ++ } ++#endif + } + + Assembler::~Assembler() { +@@ -546,6 +552,14 @@ void Assembler::Reset() { + no_const_pool_before_ = 0; + } + ++#if defined(V8_OS_WIN) ++win64_unwindinfo::BuiltinUnwindInfo Assembler::GetUnwindInfo() const { ++ DCHECK(options().collect_win64_unwind_info); ++ DCHECK_NOT_NULL(xdata_encoder_); ++ return xdata_encoder_->unwinding_info(); ++} ++#endif ++ + void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { + DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty()); + for (auto& request : heap_object_requests_) { +@@ -1395,6 +1409,12 @@ void Assembler::ldp(const CPURegister& rt, const CPURegister& rt2, + void Assembler::stp(const CPURegister& rt, const CPURegister& rt2, + const MemOperand& dst) { + LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2)); ++ ++#if defined(V8_OS_WIN) ++ if (xdata_encoder_ && rt == x29 && rt2 == lr && dst.base().IsSP()) { ++ xdata_encoder_->onSaveFpLr(); ++ } ++#endif + } + + void Assembler::ldpsw(const Register& rt, const Register& rt2, +diff --git a/src/codegen/arm64/assembler-arm64.h b/src/codegen/arm64/assembler-arm64.h +index fb5feb23074ac888e85a3676c1cbbb63126e72d5..7d1f10ad1132a51d5e93a0866ed2f13c4c9d4857 100644 +--- a/src/codegen/arm64/assembler-arm64.h ++++ b/src/codegen/arm64/assembler-arm64.h +@@ -25,6 +25,10 @@ + #undef mvn + #endif + ++#if defined(V8_OS_WIN) ++#include "src/diagnostics/unwinding-info-win64.h" ++#endif // V8_OS_WIN ++ + namespace v8 { + namespace internal { + +@@ -2452,6 +2456,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { + DISALLOW_IMPLICIT_CONSTRUCTORS(BlockPoolsScope); + }; + ++#if defined(V8_OS_WIN) ++ win64_unwindinfo::XdataEncoder* GetXdataEncoder() { ++ return xdata_encoder_.get(); ++ } ++ ++ win64_unwindinfo::BuiltinUnwindInfo GetUnwindInfo() const; ++#endif ++ + protected: + inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const; + +@@ -2774,6 +2786,10 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { + // veneer margin (or kMaxInt if there are no unresolved branches). + int next_veneer_pool_check_; + ++#if defined(V8_OS_WIN) ++ std::unique_ptr xdata_encoder_; ++#endif ++ + private: + // Avoid overflows for displacements etc. + static const int kMaximalBufferSize = 512 * MB; +diff --git a/src/codegen/arm64/macro-assembler-arm64.cc b/src/codegen/arm64/macro-assembler-arm64.cc +index aab9fc79a2c2c25e7f97a8bd41b3e25a1f2f0af1..6c559549759b198734154abf36353e6d730c8e46 100644 +--- a/src/codegen/arm64/macro-assembler-arm64.cc ++++ b/src/codegen/arm64/macro-assembler-arm64.cc +@@ -1302,6 +1302,14 @@ void MacroAssembler::PushCalleeSavedRegisters() { + stp(d8, d9, tos); + + stp(x29, x30, tos); ++#if defined(V8_OS_WIN) ++ // kFramePointerOffsetInPushCalleeSavedRegisters is the offset from tos at ++ // the end of this function to the saved caller's fp/x29 pointer. It includes ++ // registers from x19 to x28, which is 10 pointers defined by below stp ++ // instructions. ++ STATIC_ASSERT(kFramePointerOffsetInPushCalleeSavedRegisters == ++ 10 * kSystemPointerSize); ++#endif // defined(V8_OS_WIN) + stp(x27, x28, tos); + stp(x25, x26, tos); + stp(x23, x24, tos); +diff --git a/src/codegen/arm64/macro-assembler-arm64.h b/src/codegen/arm64/macro-assembler-arm64.h +index 6961428f35a0c052c9faf6afb3db42b9afabe0cf..651524795cdf78935220ef24bac637cd013c9aae 100644 +--- a/src/codegen/arm64/macro-assembler-arm64.h ++++ b/src/codegen/arm64/macro-assembler-arm64.h +@@ -83,6 +83,12 @@ inline MemOperand FieldMemOperand(Register object, int offset); + // ---------------------------------------------------------------------------- + // MacroAssembler + ++#if defined(V8_OS_WIN) ++// This offset is originated from PushCalleeSavedRegisters. ++static constexpr int kFramePointerOffsetInPushCalleeSavedRegisters = ++ 10 * kSystemPointerSize; ++#endif // V8_OS_WIN ++ + enum BranchType { + // Copies of architectural conditions. + // The associated conditions can be used in place of those, the code will +diff --git a/src/common/globals.h b/src/common/globals.h +index 5d4b957e84fc01e12854dc8fed23b967cd971dcd..b981670263f9091677591f806affc9def9044366 100644 +--- a/src/common/globals.h ++++ b/src/common/globals.h +@@ -101,6 +101,14 @@ constexpr int kStackSpaceRequiredForCompilation = 40; + #define V8_OS_WIN_X64 true + #endif + ++#if defined(V8_OS_WIN) && defined(V8_TARGET_ARCH_ARM64) ++#define V8_OS_WIN_ARM64 true ++#endif ++ ++#if defined(V8_OS_WIN_X64) || defined(V8_OS_WIN_ARM64) ++#define V8_OS_WIN64 true ++#endif ++ + // Superclass for classes only using static method functions. + // The subclass of AllStatic cannot be instantiated at all. + class AllStatic { +diff --git a/src/compiler/backend/code-generator.cc b/src/compiler/backend/code-generator.cc +index bb83a8497bbe3e7a398eeb65b5050673311cbd6a..5d20d88cd1351184cac02d69eda4b9455fef328d 100644 +--- a/src/compiler/backend/code-generator.cc ++++ b/src/compiler/backend/code-generator.cc +@@ -396,12 +396,12 @@ MaybeHandle CodeGenerator::FinalizeCode() { + CodeDesc desc; + tasm()->GetCode(isolate(), &desc, safepoints(), handler_table_offset_); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (Builtins::IsBuiltinId(info_->builtin_index())) { + isolate_->SetBuiltinUnwindData(info_->builtin_index(), + tasm()->GetUnwindInfo()); + } +-#endif ++#endif // V8_OS_WIN64 + + if (unwinding_info_writer_.eh_frame_writer()) { + unwinding_info_writer_.eh_frame_writer()->GetEhFrame(&desc); +diff --git a/src/diagnostics/unwinding-info-win64.cc b/src/diagnostics/unwinding-info-win64.cc +index 8fb01dba9a55c75de677286baa19bb9edae74231..6cc53da51f16a45c3a8ad14ca0b2150bed43d766 100644 +--- a/src/diagnostics/unwinding-info-win64.cc ++++ b/src/diagnostics/unwinding-info-win64.cc +@@ -4,12 +4,18 @@ + + #include "src/diagnostics/unwinding-info-win64.h" + +-#if defined(V8_OS_WIN_X64) +- + #include "src/codegen/macro-assembler.h" +-#include "src/codegen/x64/assembler-x64.h" + #include "src/utils/allocation.h" + ++#if defined(V8_OS_WIN_X64) ++#include "src/codegen/x64/assembler-x64.h" ++#elif defined(V8_OS_WIN_ARM64) ++#include "src/codegen/arm64/assembler-arm64-inl.h" ++#include "src/codegen/arm64/macro-assembler-arm64-inl.h" ++#else ++#error "Unsupported OS" ++#endif // V8_OS_WIN_X64 ++ + namespace v8 { + namespace internal { + namespace win64_unwindinfo { +@@ -22,9 +28,36 @@ bool CanRegisterUnwindInfoForNonABICompliantCodeRange() { + + bool RegisterUnwindInfoForExceptionHandlingOnly() { + DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange()); ++#if defined(V8_OS_WIN_ARM64) ++ return !FLAG_win64_unwinding_info; ++#else + return !IsWindows8OrGreater() || !FLAG_win64_unwinding_info; ++#endif ++} ++ ++v8::UnhandledExceptionCallback unhandled_exception_callback_g = nullptr; ++ ++void SetUnhandledExceptionCallback( ++ v8::UnhandledExceptionCallback unhandled_exception_callback) { ++ unhandled_exception_callback_g = unhandled_exception_callback; ++} ++ ++// This function is registered as exception handler for V8-generated code as ++// part of the registration of unwinding info. It is referenced by ++// RegisterNonABICompliantCodeRange(), below, and by the unwinding info for ++// builtins declared in the embedded blob. ++extern "C" __declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME( ++ PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame, ++ PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext) { ++ if (unhandled_exception_callback_g != nullptr) { ++ EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord}; ++ return unhandled_exception_callback_g(&info); ++ } ++ return ExceptionContinueSearch; + } + ++#if defined(V8_OS_WIN_X64) ++ + #pragma pack(push, 1) + + /* +@@ -49,9 +82,12 @@ struct UNWIND_INFO { + unsigned char FrameOffset : 4; + }; + ++static constexpr int kNumberOfUnwindCodes = 2; ++static constexpr int kMaxExceptionThunkSize = 12; ++ + struct V8UnwindData { + UNWIND_INFO unwind_info; +- UNWIND_CODE unwind_codes[2]; ++ UNWIND_CODE unwind_codes[kNumberOfUnwindCodes]; + + V8UnwindData() { + static constexpr int kOpPushNonvol = 0; +@@ -87,46 +123,244 @@ struct ExceptionHandlerUnwindData { + } + }; + ++struct CodeRangeUnwindingRecord { ++ void* dynamic_table; ++ uint32_t runtime_function_count; ++ V8UnwindData unwind_info; ++ uint32_t exception_handler; ++ uint8_t exception_thunk[kMaxExceptionThunkSize]; ++ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount]; ++}; ++ ++struct ExceptionHandlerRecord { ++ uint32_t runtime_function_count; ++ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount]; ++ ExceptionHandlerUnwindData unwind_info; ++ uint32_t exception_handler; ++ uint8_t exception_thunk[kMaxExceptionThunkSize]; ++}; ++ + #pragma pack(pop) + +-v8::UnhandledExceptionCallback unhandled_exception_callback_g = nullptr; ++std::vector GetUnwindInfoForBuiltinFunctions() { ++ V8UnwindData xdata; ++ return std::vector( ++ reinterpret_cast(&xdata), ++ reinterpret_cast(&xdata) + sizeof(xdata)); ++} + +-void SetUnhandledExceptionCallback( +- v8::UnhandledExceptionCallback unhandled_exception_callback) { +- unhandled_exception_callback_g = unhandled_exception_callback; ++template ++void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) { ++ // We assume that the first page of the code range is executable and ++ // committed and reserved to contain PDATA/XDATA. ++ ++ // All addresses are 32bit relative offsets to start. ++ record->runtime_function[0].BeginAddress = 0; ++ record->runtime_function[0].EndAddress = ++ static_cast(code_size_in_bytes); ++ record->runtime_function[0].UnwindData = offsetof(Record, unwind_info); ++ record->runtime_function_count = 1; ++ record->exception_handler = offsetof(Record, exception_thunk); ++ ++ // Hardcoded thunk. ++ AssemblerOptions options; ++ options.record_reloc_info_for_serialization = false; ++ MacroAssembler masm(nullptr, options, CodeObjectRequired::kNo, ++ NewAssemblerBuffer(64)); ++ masm.movq(rax, reinterpret_cast(&CRASH_HANDLER_FUNCTION_NAME)); ++ masm.jmp(rax); ++ DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk)); ++ memcpy(&record->exception_thunk[0], masm.buffer_start(), ++ masm.instruction_size()); + } + +-// This function is registered as exception handler for V8-generated code as +-// part of the registration of unwinding info. It is referenced by +-// RegisterNonABICompliantCodeRange(), below, and by the unwinding info for +-// builtins declared in the embedded blob. +-extern "C" __declspec(dllexport) int CRASH_HANDLER_FUNCTION_NAME( +- PEXCEPTION_RECORD ExceptionRecord, ULONG64 EstablisherFrame, +- PCONTEXT ContextRecord, PDISPATCHER_CONTEXT DispatcherContext) { +- if (unhandled_exception_callback_g != nullptr) { +- EXCEPTION_POINTERS info = {ExceptionRecord, ContextRecord}; +- return unhandled_exception_callback_g(&info); +- } +- return ExceptionContinueSearch; ++#elif defined(V8_OS_WIN_ARM64) ++ ++#pragma pack(push, 1) ++ ++// ARM64 unwind codes are defined in below doc. ++// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes ++enum UnwindOp8Bit { ++ OpNop = 0xE3, ++ OpSaveFpLr = 0x40, ++ OpSaveFpLrX = 0x80, ++ OpSetFp = 0xE1, ++ OpEnd = 0xE4, ++}; ++ ++typedef uint32_t UNWIND_CODE; ++ ++constexpr UNWIND_CODE Combine8BitUnwindCodes(uint8_t code0, ++ uint8_t code1 = OpNop, ++ uint8_t code2 = OpNop, ++ uint8_t code3 = OpNop) { ++ return static_cast(code0) | (static_cast(code1) << 8) | ++ (static_cast(code2) << 16) | ++ (static_cast(code3) << 24); + } + +-static constexpr int kMaxExceptionThunkSize = 12; ++// UNWIND_INFO defines the static part (first 32-bit) of the .xdata record in ++// below doc. ++// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records ++struct UNWIND_INFO { ++ uint32_t FunctionLength : 18; ++ uint32_t Version : 2; ++ uint32_t X : 1; ++ uint32_t E : 1; ++ uint32_t EpilogCount : 5; ++ uint32_t CodeWords : 5; ++}; ++ ++static constexpr int kNumberOfUnwindCodes = 1; ++static constexpr int kMaxExceptionThunkSize = 16; ++static constexpr int kFunctionLengthShiftSize = 2; ++static constexpr int kFunctionLengthMask = (1 << kFunctionLengthShiftSize) - 1; ++static constexpr int kFramePointerAdjustmentShiftSize = 3; ++static constexpr int kFramePointerAdjustmentShiftMask = ++ (1 << kFramePointerAdjustmentShiftSize) - 1; ++ ++struct V8UnwindData { ++ UNWIND_INFO unwind_info; ++ UNWIND_CODE unwind_codes[kNumberOfUnwindCodes]; ++ ++ V8UnwindData() { ++ memset(&unwind_info, 0, sizeof(UNWIND_INFO)); ++ unwind_info.X = 1; // has exception handler after unwind-codes. ++ unwind_info.CodeWords = 1; ++ ++ // stp fp, lr, [sp, #offset]! ++ unwind_codes[0] = Combine8BitUnwindCodes(OpSetFp, OpSaveFpLrX, OpEnd); ++ } ++}; + + struct CodeRangeUnwindingRecord { +- RUNTIME_FUNCTION runtime_function; ++ void* dynamic_table; ++ uint32_t runtime_function_count; + V8UnwindData unwind_info; + uint32_t exception_handler; +- uint8_t exception_thunk[kMaxExceptionThunkSize]; +- void* dynamic_table; +-}; + +-struct ExceptionHandlerRecord { +- RUNTIME_FUNCTION runtime_function; +- ExceptionHandlerUnwindData unwind_info; +- uint32_t exception_handler; ++ // For Windows ARM64 unwinding, register 2 unwind_info for each code range, ++ // unwind_info for all full size ranges (1MB - 4 bytes) and unwind_info1 for ++ // the remaining non full size range. There is at most 1 range which is less ++ // than full size. ++ V8UnwindData unwind_info1; ++ uint32_t exception_handler1; + uint8_t exception_thunk[kMaxExceptionThunkSize]; ++ ++ // More RUNTIME_FUNCTION structs could follow below array because the number ++ // of RUNTIME_FUNCTION needed to cover given code range is computed at ++ // runtime. ++ RUNTIME_FUNCTION runtime_function[kDefaultRuntimeFunctionCount]; + }; + ++#pragma pack(pop) ++ ++std::vector GetUnwindInfoForBuiltinFunction(uint32_t func_len, ++ int32_t fp_adjustment) { ++ DCHECK_LE(func_len, kMaxFunctionLength); ++ DCHECK_EQ((func_len & kFunctionLengthMask), 0); ++ USE(kFunctionLengthMask); ++ ++ // Unwind code save_fplr requires the offset to be within range [0, 504]. ++ // This range is defined in below doc for unwind code save_fplr. ++ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes ++ DCHECK_GE(fp_adjustment, 0); ++ DCHECK_LE(fp_adjustment, 504); ++ DCHECK_EQ((fp_adjustment & kFramePointerAdjustmentShiftMask), 0); ++ USE(kFramePointerAdjustmentShiftMask); ++ ++ V8UnwindData xdata; ++ // FunctionLength is ensured to be aligned at instruction size and Windows ++ // ARM64 doesn't encoding its 2 LSB. ++ xdata.unwind_info.FunctionLength = func_len >> kFunctionLengthShiftSize; ++ xdata.unwind_info.CodeWords = 1; ++ xdata.unwind_codes[0] = Combine8BitUnwindCodes( ++ OpSetFp, ++ (OpSaveFpLr | (fp_adjustment >> kFramePointerAdjustmentShiftSize)), ++ OpEnd); ++ ++ return std::vector( ++ reinterpret_cast(&xdata), ++ reinterpret_cast(&xdata) + sizeof(xdata)); ++} ++ ++template ++void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) { ++ // We assume that the first page of the code range is executable and ++ // committed and reserved to contain multiple PDATA/XDATA to cover the whole ++ // range. All addresses are 32bit relative offsets to start. ++ ++ // Maximum RUNTIME_FUNCTION count available in reserved memory, this includes ++ // static part in Record as kDefaultRuntimeFunctionCount plus dynamic part in ++ // the remaining reserved memory. ++ constexpr uint32_t max_runtime_function_count = static_cast( ++ (kOSPageSize - sizeof(Record)) / sizeof(RUNTIME_FUNCTION) + ++ kDefaultRuntimeFunctionCount); ++ ++ uint32_t runtime_function_index = 0; ++ uint32_t current_unwind_start_address = 0; ++ int64_t remaining_size_in_bytes = static_cast(code_size_in_bytes); ++ ++ // Divide the code range into chunks in size kMaxFunctionLength and create a ++ // RUNTIME_FUNCTION for each of them. All the chunks in the same size can ++ // share 1 unwind_info struct, but a separate unwind_info is needed for the ++ // last chunk if it is smaller than kMaxFunctionLength, because unlike X64, ++ // unwind_info encodes the function/chunk length. ++ while (remaining_size_in_bytes >= kMaxFunctionLength && ++ runtime_function_index < max_runtime_function_count) { ++ record->runtime_function[runtime_function_index].BeginAddress = ++ current_unwind_start_address; ++ record->runtime_function[runtime_function_index].UnwindData = ++ static_cast(offsetof(Record, unwind_info)); ++ ++ runtime_function_index++; ++ current_unwind_start_address += kMaxFunctionLength; ++ remaining_size_in_bytes -= kMaxFunctionLength; ++ } ++ // FunctionLength is ensured to be aligned at instruction size and Windows ++ // ARM64 doesn't encoding 2 LSB. ++ record->unwind_info.unwind_info.FunctionLength = kMaxFunctionLength >> 2; ++ ++ if (remaining_size_in_bytes > 0 && ++ runtime_function_index < max_runtime_function_count) { ++ DCHECK_EQ(remaining_size_in_bytes % kInstrSize, 0); ++ ++ record->unwind_info1.unwind_info.FunctionLength = static_cast( ++ remaining_size_in_bytes >> kFunctionLengthShiftSize); ++ record->runtime_function[runtime_function_index].BeginAddress = ++ current_unwind_start_address; ++ record->runtime_function[runtime_function_index].UnwindData = ++ static_cast(offsetof(Record, unwind_info1)); ++ ++ remaining_size_in_bytes -= kMaxFunctionLength; ++ record->exception_handler1 = offsetof(Record, exception_thunk); ++ record->runtime_function_count = runtime_function_index + 1; ++ } else { ++ record->runtime_function_count = runtime_function_index; ++ } ++ ++ // 1 page can cover kMaximalCodeRangeSize for ARM64 (128MB). If ++ // kMaximalCodeRangeSize is changed for ARM64 and makes 1 page insufficient to ++ // cover it, more pages will need to reserved for unwind data. ++ DCHECK_LE(remaining_size_in_bytes, 0); ++ ++ record->exception_handler = offsetof(Record, exception_thunk); ++ ++ // Hardcoded thunk. ++ AssemblerOptions options; ++ options.record_reloc_info_for_serialization = false; ++ TurboAssembler masm(nullptr, options, CodeObjectRequired::kNo, ++ NewAssemblerBuffer(64)); ++ masm.Mov(x16, ++ Operand(reinterpret_cast(&CRASH_HANDLER_FUNCTION_NAME))); ++ masm.Br(x16); ++ DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk)); ++ memcpy(&record->exception_thunk[0], masm.buffer_start(), ++ masm.instruction_size()); ++} ++ ++#endif // V8_OS_WIN_X64 ++ + namespace { + + V8_DECLARE_ONCE(load_ntdll_unwinding_functions_once); +@@ -185,37 +419,6 @@ void DeleteGrowableFunctionTable(PVOID dynamic_table) { + + } // namespace + +-std::vector GetUnwindInfoForBuiltinFunctions() { +- V8UnwindData xdata; +- return std::vector( +- reinterpret_cast(&xdata), +- reinterpret_cast(&xdata) + sizeof(xdata)); +-} +- +-template +-void InitUnwindingRecord(Record* record, size_t code_size_in_bytes) { +- // We assume that the first page of the code range is executable and +- // committed and reserved to contain PDATA/XDATA. +- +- // All addresses are 32bit relative offsets to start. +- record->runtime_function.BeginAddress = 0; +- record->runtime_function.EndAddress = static_cast(code_size_in_bytes); +- record->runtime_function.UnwindData = offsetof(Record, unwind_info); +- +- record->exception_handler = offsetof(Record, exception_thunk); +- +- // Hardcoded thunk. +- AssemblerOptions options; +- options.record_reloc_info_for_serialization = false; +- MacroAssembler masm(nullptr, options, CodeObjectRequired::kNo, +- NewAssemblerBuffer(64)); +- masm.movq(rax, reinterpret_cast(&CRASH_HANDLER_FUNCTION_NAME)); +- masm.jmp(rax); +- DCHECK_LE(masm.instruction_size(), sizeof(record->exception_thunk)); +- memcpy(&record->exception_thunk[0], masm.buffer_start(), +- masm.instruction_size()); +-} +- + void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { + DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange()); + +@@ -231,24 +434,30 @@ void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { + // by the embedder (like Crashpad). + + if (RegisterUnwindInfoForExceptionHandlingOnly()) { ++#if defined(V8_OS_WIN_X64) ++ // Windows ARM64 starts since 1709 Windows build, no need to have exception ++ // handling only unwind info for compatibility. + if (unhandled_exception_callback_g) { + ExceptionHandlerRecord* record = new (start) ExceptionHandlerRecord(); + InitUnwindingRecord(record, size_in_bytes); + +- CHECK(::RtlAddFunctionTable(&record->runtime_function, 1, ++ CHECK(::RtlAddFunctionTable(record->runtime_function, ++ kDefaultRuntimeFunctionCount, + reinterpret_cast(start))); + + // Protect reserved page against modifications. + DWORD old_protect; +- CHECK(VirtualProtect(start, sizeof(CodeRangeUnwindingRecord), ++ CHECK(VirtualProtect(start, sizeof(ExceptionHandlerRecord), + PAGE_EXECUTE_READ, &old_protect)); + } ++#endif // V8_OS_WIN_X64 + } else { + CodeRangeUnwindingRecord* record = new (start) CodeRangeUnwindingRecord(); + InitUnwindingRecord(record, size_in_bytes); + + CHECK(AddGrowableFunctionTable( +- &record->dynamic_table, &record->runtime_function, 1, 1, ++ &record->dynamic_table, record->runtime_function, ++ record->runtime_function_count, record->runtime_function_count, + reinterpret_cast(start), + reinterpret_cast(reinterpret_cast(start) + + size_in_bytes))); +@@ -264,11 +473,15 @@ void UnregisterNonABICompliantCodeRange(void* start) { + DCHECK(CanRegisterUnwindInfoForNonABICompliantCodeRange()); + + if (RegisterUnwindInfoForExceptionHandlingOnly()) { ++#if defined(V8_OS_WIN_X64) ++ // Windows ARM64 starts since 1709 Windows build, no need to have exception ++ // handling only unwind info for compatibility. + if (unhandled_exception_callback_g) { + ExceptionHandlerRecord* record = + reinterpret_cast(start); +- CHECK(::RtlDeleteFunctionTable(&record->runtime_function)); ++ CHECK(::RtlDeleteFunctionTable(record->runtime_function)); + } ++#endif // V8_OS_WIN_X64 + } else { + CodeRangeUnwindingRecord* record = + reinterpret_cast(start); +@@ -278,19 +491,41 @@ void UnregisterNonABICompliantCodeRange(void* start) { + } + } + ++#if defined(V8_OS_WIN_X64) ++ + void XdataEncoder::onPushRbp() { +- current_push_rbp_offset_ = assembler_.pc_offset() - kPushRbpInstructionLength; ++ current_frame_code_offset_ = ++ assembler_.pc_offset() - kPushRbpInstructionLength; + } + + void XdataEncoder::onMovRbpRsp() { +- if (current_push_rbp_offset_ >= 0 && +- current_push_rbp_offset_ == assembler_.pc_offset() - kRbpPrefixLength) { +- fp_offsets_.push_back(current_push_rbp_offset_); ++ if (current_frame_code_offset_ >= 0 && ++ current_frame_code_offset_ == assembler_.pc_offset() - kRbpPrefixLength) { ++ fp_offsets_.push_back(current_frame_code_offset_); ++ } ++} ++ ++#elif defined(V8_OS_WIN_ARM64) ++ ++void XdataEncoder::onSaveFpLr() { ++ current_frame_code_offset_ = assembler_.pc_offset() - 4; ++ fp_offsets_.push_back(current_frame_code_offset_); ++ fp_adjustments_.push_back(current_frame_adjustment_); ++ if (current_frame_adjustment_ != 0) { ++ current_frame_adjustment_ = 0; + } + } + ++void XdataEncoder::onFramePointerAdjustment(int bytes) { ++ // According to below doc, offset for save_fplr is aligned to pointer size. ++ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#unwind-codes ++ DCHECK_EQ((bytes & kPointerAlignmentMask), 0); ++ ++ current_frame_adjustment_ = bytes; ++} ++ ++#endif // V8_OS_WIN_X64 ++ + } // namespace win64_unwindinfo + } // namespace internal + } // namespace v8 +- +-#endif // defined(V8_OS_WIN_X64) +diff --git a/src/diagnostics/unwinding-info-win64.h b/src/diagnostics/unwinding-info-win64.h +index f6611e7e2ec5a8afc1769886593f112eb4ad0f89..12092cc06a77aca9a63d01731750e1a24cf13980 100644 +--- a/src/diagnostics/unwinding-info-win64.h ++++ b/src/diagnostics/unwinding-info-win64.h +@@ -9,7 +9,7 @@ + #include "include/v8config.h" + #include "src/common/globals.h" + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/base/win32-headers.h" + + namespace v8 { +@@ -21,11 +21,7 @@ namespace win64_unwindinfo { + #define CRASH_HANDLER_FUNCTION_NAME_STRING \ + "CrashForExceptionInNonABICompliantCodeRange" + +-static const int kPushRbpInstructionLength = 1; +-static const int kMovRbpRspInstructionLength = 3; +-static const int kRbpPrefixCodes = 2; +-static const int kRbpPrefixLength = +- kPushRbpInstructionLength + kMovRbpRspInstructionLength; ++static constexpr int kOSPageSize = 4096; + + /** + * Returns true if V8 is configured to emit unwinding data for embedded in the +@@ -50,15 +46,33 @@ bool CanRegisterUnwindInfoForNonABICompliantCodeRange(); + void SetUnhandledExceptionCallback( + v8::UnhandledExceptionCallback unhandled_exception_callback); + ++void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes); ++void UnregisterNonABICompliantCodeRange(void* start); ++ + /** +- * Returns a vector of bytes that contains the Win64 unwind data used for all ++ * 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 ++ * isolate or WASM module. For Windows ARM64, 1 RUNTIME_FUNCTION covers ++ * kMaxFunctionLength bytes so multiple RUNTIME_FUNCTION structs could be needed ++ * to cover the whole code range of an isolate or WASM module. The extra ++ * RUNTIME_FUNCTIONs are assumed following the first one in the reserved page. ++ */ ++static constexpr 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 + * V8 builtin functions. + */ + std::vector GetUnwindInfoForBuiltinFunctions(); + +-void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes); +-void UnregisterNonABICompliantCodeRange(void* start); +- + class BuiltinUnwindInfo { + public: + BuiltinUnwindInfo() : is_leaf_function_(true) {} +@@ -76,7 +90,7 @@ class BuiltinUnwindInfo { + class XdataEncoder { + public: + explicit XdataEncoder(const Assembler& assembler) +- : assembler_(assembler), current_push_rbp_offset_(-1) {} ++ : assembler_(assembler), current_frame_code_offset_(-1) {} + + void onPushRbp(); + void onMovRbpRsp(); +@@ -88,14 +102,77 @@ class XdataEncoder { + private: + const Assembler& assembler_; + std::vector fp_offsets_; +- int current_push_rbp_offset_; ++ int current_frame_code_offset_; + }; + +-} // namespace win64_unwindinfo ++#elif defined(V8_OS_WIN_ARM64) + ++/** ++ * 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 constexpr int kMaxFunctionLength = ((1 << 18) - 1) << 2; ++ ++/** ++ * 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. ++ */ ++std::vector GetUnwindInfoForBuiltinFunction(uint32_t func_len, ++ int32_t fp_adjustment); ++class BuiltinUnwindInfo { ++ public: ++ BuiltinUnwindInfo() : is_leaf_function_(true) {} ++ explicit BuiltinUnwindInfo(const std::vector& fp_offsets, ++ const std::vector& fp_adjustments) ++ : is_leaf_function_(false), ++ fp_offsets_(fp_offsets), ++ fp_adjustments_(fp_adjustments) {} ++ ++ const std::vector& fp_adjustments() const { return fp_adjustments_; } ++ ++ bool is_leaf_function() const { return is_leaf_function_; } ++ const std::vector& fp_offsets() const { return fp_offsets_; } ++ ++ private: ++ bool is_leaf_function_; ++ std::vector fp_offsets_; ++ std::vector fp_adjustments_; ++}; ++ ++class XdataEncoder { ++ public: ++ explicit XdataEncoder(const Assembler& assembler) ++ : assembler_(assembler), ++ current_frame_code_offset_(-1), ++ current_frame_adjustment_(0) {} ++ ++ void onSaveFpLr(); ++ void onFramePointerAdjustment(int bytes); ++ ++ BuiltinUnwindInfo unwinding_info() const { ++ return BuiltinUnwindInfo(fp_offsets_, fp_adjustments_); ++ } ++ ++ private: ++ const Assembler& assembler_; ++ std::vector fp_offsets_; ++ int current_frame_code_offset_; ++ int current_frame_adjustment_; ++ std::vector fp_adjustments_; ++}; ++ ++#endif ++ ++} // namespace win64_unwindinfo + } // namespace internal + } // namespace v8 + +-#endif // defined(V8_OS_WIN_X64) ++#endif // V8_OS_WIN64 + + #endif // V8_DIAGNOSTICS_UNWINDING_INFO_WIN64_H_ +diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc +index 8a8db12ca3f59577436d148bb2693c836720af2d..380131730c7e87eced53d7a4d68d328cc9b01b8a 100644 +--- a/src/execution/isolate.cc ++++ b/src/execution/isolate.cc +@@ -85,9 +85,9 @@ + #include "unicode/uobject.h" + #endif // V8_INTL_SUPPORT + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif ++#endif // V8_OS_WIN64 + + extern "C" const uint8_t* v8_Default_embedded_blob_; + extern "C" uint32_t v8_Default_embedded_blob_size_; +@@ -2935,7 +2935,7 @@ void Isolate::Deinit() { + heap_profiler()->StopSamplingHeapProfiler(); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() && + heap()->memory_allocator()) { + const base::AddressRegion& code_range = +@@ -2943,7 +2943,7 @@ void Isolate::Deinit() { + void* start = reinterpret_cast(code_range.begin()); + win64_unwindinfo::UnregisterNonABICompliantCodeRange(start); + } +-#endif ++#endif // V8_OS_WIN64 + + debug()->Unload(); + +@@ -3512,7 +3512,7 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer, + sampling_flags); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + const base::AddressRegion& code_range = + heap()->memory_allocator()->code_range(); +@@ -3520,7 +3520,7 @@ bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer, + size_t size_in_bytes = code_range.size(); + win64_unwindinfo::RegisterNonABICompliantCodeRange(start, size_in_bytes); + } +-#endif ++#endif // V8_OS_WIN64 + + if (create_heap_objects && FLAG_profile_deserialization) { + double ms = timer.Elapsed().InMillisecondsF(); +@@ -4324,7 +4324,7 @@ void Isolate::PrepareBuiltinSourcePositionMap() { + } + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void Isolate::SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) { +@@ -4332,7 +4332,7 @@ void Isolate::SetBuiltinUnwindData( + embedded_file_writer_->SetBuiltinUnwindData(builtin_index, unwinding_info); + } + } +-#endif ++#endif // V8_OS_WIN64 + + void Isolate::SetPrepareStackTraceCallback(PrepareStackTraceCallback callback) { + prepare_stack_trace_callback_ = callback; +diff --git a/src/execution/isolate.h b/src/execution/isolate.h +index 4b4bf9cd7c61687b0f36da1eaa672979c59dab67..33e43c81113ea88d611aa134edc82c2e6d06cfde 100644 +--- a/src/execution/isolate.h ++++ b/src/execution/isolate.h +@@ -1484,11 +1484,11 @@ class Isolate final : private HiddenFactory { + // annotate the builtin blob with debugging information. + void PrepareBuiltinSourcePositionMap(); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info); +-#endif ++#endif // V8_OS_WIN64 + + void SetPrepareStackTraceCallback(PrepareStackTraceCallback callback); + MaybeHandle RunPrepareStackTraceCallback(Handle, +diff --git a/src/snapshot/embedded/embedded-file-writer.cc b/src/snapshot/embedded/embedded-file-writer.cc +index 4703ef48224f9f155ef2f8f0cd47507968a3fdfe..5f57993fc3255a68ce6ebcc2368b1c02b1953eff 100644 +--- a/src/snapshot/embedded/embedded-file-writer.cc ++++ b/src/snapshot/embedded/embedded-file-writer.cc +@@ -92,7 +92,7 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w, + w->Newline(); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + { + i::EmbeddedVector unwind_info_symbol; + i::SNPrintF(unwind_info_symbol, "%s_Builtins_UnwindInfo", +@@ -102,7 +102,7 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w, + EmbeddedBlobDataSymbol().c_str(), blob, + reinterpret_cast(&unwind_infos_[0])); + } +-#endif ++#endif // V8_OS_WIN64 + + w->FileEpilogue(); + } +diff --git a/src/snapshot/embedded/embedded-file-writer.h b/src/snapshot/embedded/embedded-file-writer.h +index c26465ae6a7d26b799ad2582784973638fbd41cd..e487b9be9bcc77e97d2da6109e1218f3fee69ce4 100644 +--- a/src/snapshot/embedded/embedded-file-writer.h ++++ b/src/snapshot/embedded/embedded-file-writer.h +@@ -13,9 +13,9 @@ + #include "src/snapshot/embedded/embedded-data.h" + #include "src/snapshot/embedded/platform-embedded-file-writer-base.h" + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif ++#endif // V8_OS_WIN64 + + namespace v8 { + namespace internal { +@@ -35,11 +35,11 @@ class EmbeddedFileWriterInterface { + // compiled builtin Code objects with trampolines. + virtual void PrepareBuiltinSourcePositionMap(Builtins* builtins) = 0; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + virtual void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) = 0; +-#endif ++#endif // V8_OS_WIN64 + }; + + // Generates the embedded.S file which is later compiled into the final v8 +@@ -59,14 +59,14 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { + + void PrepareBuiltinSourcePositionMap(Builtins* builtins) override; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void SetBuiltinUnwindData( + int builtin_index, + const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override { + DCHECK_LT(builtin_index, Builtins::builtin_count); + unwind_infos_[builtin_index] = unwinding_info; + } +-#endif ++#endif // V8_OS_WIN64 + + void SetEmbeddedFile(const char* embedded_src_path) { + embedded_src_path_ = embedded_src_path; +@@ -172,9 +172,6 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { + const i::EmbeddedData* blob) const; + + #if defined(V8_OS_WIN_X64) +- std::string BuiltinsUnwindInfoLabel() const; +- void WriteUnwindInfo(PlatformEmbeddedFileWriterBase* w, +- const i::EmbeddedData* blob) const; + void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterBase* w, + uint64_t rva_start, uint64_t rva_end) const; + #endif +@@ -194,9 +191,9 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface { + private: + std::vector source_positions_[Builtins::builtin_count]; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + win64_unwindinfo::BuiltinUnwindInfo unwind_infos_[Builtins::builtin_count]; +-#endif ++#endif // V8_OS_WIN64 + + std::map external_filenames_; + std::vector external_filenames_by_index_; +diff --git a/src/snapshot/embedded/platform-embedded-file-writer-win.cc b/src/snapshot/embedded/platform-embedded-file-writer-win.cc +index 69457e11a5537a6500b20adb43051e25f645403f..9a9a26fbd0abef6f5b1967cdbd5fe3fcbaef4f20 100644 +--- a/src/snapshot/embedded/platform-embedded-file-writer-win.cc ++++ b/src/snapshot/embedded/platform-embedded-file-writer-win.cc +@@ -6,13 +6,14 @@ + + #include + +-#include "src/common/globals.h" // For V8_OS_WIN_X64. ++#include "src/common/globals.h" // For V8_OS_WIN64 + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/builtins/builtins.h" + #include "src/diagnostics/unwinding-info-win64.h" + #include "src/snapshot/embedded/embedded-data.h" +-#endif ++#include "src/snapshot/embedded/embedded-file-writer.h" ++#endif // V8_OS_WIN64 + + namespace v8 { + namespace internal { +@@ -213,20 +214,118 @@ void EmitUnwindData(PlatformEmbeddedFileWriterWin* w, + w->EndPdataSection(); + w->Newline(); + } +-#endif // defined(V8_OS_WIN_X64) ++ ++#elif defined(V8_OS_WIN_ARM64) ++ ++void EmitUnwindData(PlatformEmbeddedFileWriterWin* w, ++ const char* unwind_info_symbol, ++ const char* embedded_blob_data_symbol, ++ const EmbeddedData* blob, ++ const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) { ++ DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins()); ++ ++ // Fairly arbitrary but should fit all symbol names. ++ static constexpr int kTemporaryStringLength = 256; ++ i::EmbeddedVector unwind_info_full_symbol; ++ ++ // Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as ++ // documented here: ++ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling. ++ w->Comment( ++ "pdata for all the code in the embedded blob (structs of type " ++ "RUNTIME_FUNCTION)."); ++ w->Comment(" BeginAddress"); ++ w->Comment(" UnwindInfoAddress"); ++ w->StartPdataSection(); ++ std::vector code_chunks; ++ std::vector fp_adjustments; ++ ++ for (int i = 0; i < Builtins::builtin_count; i++) { ++ if (!blob->ContainsBuiltin(i)) continue; ++ if (unwind_infos[i].is_leaf_function()) continue; ++ ++ uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) - ++ reinterpret_cast
(blob->data()); ++ uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i); ++ ++ const std::vector& xdata_desc = unwind_infos[i].fp_offsets(); ++ const std::vector& xdata_fp_adjustments = ++ unwind_infos[i].fp_adjustments(); ++ DCHECK_EQ(xdata_desc.size(), xdata_fp_adjustments.size()); ++ ++ for (size_t j = 0; j < xdata_desc.size(); j++) { ++ int chunk_start = xdata_desc[j]; ++ int chunk_end = ++ (j < xdata_desc.size() - 1) ? xdata_desc[j + 1] : builtin_size; ++ int chunk_len = ::RoundUp(chunk_end - chunk_start, kInstrSize); ++ ++ while (chunk_len > 0) { ++ int allowed_chunk_len = ++ std::min(chunk_len, win64_unwindinfo::kMaxFunctionLength); ++ chunk_len -= win64_unwindinfo::kMaxFunctionLength; ++ ++ // Record the chunk length and fp_adjustment for emitting UNWIND_INFO ++ // later. ++ code_chunks.push_back(allowed_chunk_len); ++ fp_adjustments.push_back(xdata_fp_adjustments[j]); ++ i::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol, ++ code_chunks.size()); ++ w->DeclareRvaToSymbol(embedded_blob_data_symbol, ++ builtin_start_offset + chunk_start); ++ w->DeclareRvaToSymbol(unwind_info_full_symbol.begin()); ++ } ++ } ++ } ++ w->EndPdataSection(); ++ w->Newline(); ++ ++ // Emit an UNWIND_INFO (XDATA) structs, which contains the unwinding ++ // information. ++ w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING); ++ w->StartXdataSection(); ++ { ++ for (size_t i = 0; i < code_chunks.size(); i++) { ++ i::SNPrintF(unwind_info_full_symbol, "%s_%u", unwind_info_symbol, i + 1); ++ w->DeclareLabel(unwind_info_full_symbol.begin()); ++ std::vector xdata = ++ win64_unwindinfo::GetUnwindInfoForBuiltinFunction(code_chunks[i], ++ fp_adjustments[i]); ++ ++ w->IndentedDataDirective(kByte); ++ for (size_t j = 0; j < xdata.size(); j++) { ++ if (j > 0) fprintf(w->fp(), ","); ++ w->HexLiteral(xdata[j]); ++ } ++ w->Newline(); ++ w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING); ++ } ++ } ++ w->EndXdataSection(); ++ w->Newline(); ++} ++ ++#endif // V8_OS_WIN_X64 + + } // namespace + + void PlatformEmbeddedFileWriterWin::MaybeEmitUnwindData( + const char* unwind_info_symbol, const char* embedded_blob_data_symbol, + const EmbeddedData* blob, const void* unwind_infos) { +-#if defined(V8_OS_WIN_X64) ++// Windows ARM64 supports cross build which could require unwind info for ++// host_os. Ignore this case because it is only used in build time. ++#if defined(V8_OS_WIN_ARM64) ++ if (target_arch_ != EmbeddedTargetArch::kArm64) { ++ return; ++ } ++#endif // V8_OS_WIN_ARM64 ++ ++#if defined(V8_OS_WIN64) + if (win64_unwindinfo::CanEmitUnwindInfoForBuiltins()) { + EmitUnwindData(this, unwind_info_symbol, embedded_blob_data_symbol, blob, + reinterpret_cast( + unwind_infos)); + } +-#endif // defined(V8_OS_WIN_X64) ++#endif // V8_OS_WIN64 + } + + // Windows, MSVC, not arm/arm64. +@@ -544,6 +643,7 @@ void PlatformEmbeddedFileWriterWin::DeclareFunctionBegin(const char* name) { + if (target_arch_ == EmbeddedTargetArch::kArm64) { + // Windows ARM64 assembly is in GAS syntax, but ".type" is invalid directive + // in PE/COFF for Windows. ++ DeclareSymbolGlobal(name); + } else { + // The directives for inserting debugging information on Windows come + // from the PE (Portable Executable) and COFF (Common Object File Format) +diff --git a/src/wasm/wasm-code-manager.cc b/src/wasm/wasm-code-manager.cc +index 2eddce3d956ffcfbf5c668d5eb6e778c66959e45..9be2e75c3e9ed7bfbf31dd7cbbe9c4a634b0abc4 100644 +--- a/src/wasm/wasm-code-manager.cc ++++ b/src/wasm/wasm-code-manager.cc +@@ -29,9 +29,9 @@ + #include "src/wasm/wasm-objects-inl.h" + #include "src/wasm/wasm-objects.h" + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + #include "src/diagnostics/unwinding-info-win64.h" +-#endif ++#endif // V8_OS_WIN64 + + #define TRACE_HEAP(...) \ + do { \ +@@ -630,7 +630,7 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled, + CompilationState::New(*shared_this, std::move(async_counters)); + DCHECK_NOT_NULL(module_); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + // On some platforms, specifically Win64, we need to reserve some pages at + // the beginning of an executable space. + // See src/heap/spaces.cc, MemoryAllocator::InitializeCodePageAllocator() and +@@ -640,7 +640,7 @@ NativeModule::NativeModule(WasmEngine* engine, const WasmFeatures& enabled, + ->CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + code_allocator_.AllocateForCode(this, Heap::GetCodeRangeReservedAreaSize()); + } +-#endif ++#endif // V8_OS_WIN64 + + uint32_t num_wasm_functions = module_->num_declared_functions; + if (num_wasm_functions > 0) { +@@ -1159,21 +1159,21 @@ WasmCodeManager::WasmCodeManager(WasmMemoryTracker* memory_tracker, + size_t max_committed) + : memory_tracker_(memory_tracker), + max_committed_code_space_(max_committed), +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + is_win64_unwind_info_disabled_for_testing_(false), +-#endif ++#endif // V8_OS_WIN64 + total_committed_code_space_(0), + critical_committed_code_space_(max_committed / 2) { + DCHECK_LE(max_committed, kMaxWasmCodeMemory); + } + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + bool WasmCodeManager::CanRegisterUnwindInfoForNonABICompliantCodeRange() const { + return win64_unwindinfo::CanRegisterUnwindInfoForNonABICompliantCodeRange() && + FLAG_win64_unwinding_info && + !is_win64_unwind_info_disabled_for_testing_; + } +-#endif ++#endif // V8_OS_WIN64 + + bool WasmCodeManager::Commit(base::AddressRegion region) { + // TODO(v8:8462): Remove eager commit once perf supports remapping. +@@ -1341,12 +1341,12 @@ std::shared_ptr WasmCodeManager::NewNativeModule( + TRACE_HEAP("New NativeModule %p: Mem: %" PRIuPTR ",+%zu\n", ret.get(), start, + size); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + win64_unwindinfo::RegisterNonABICompliantCodeRange( + reinterpret_cast(start), size); + } +-#endif ++#endif // V8_OS_WIN64 + + base::MutexGuard lock(&native_modules_mutex_); + lookup_map_.insert(std::make_pair(start, std::make_pair(end, ret.get()))); +@@ -1460,12 +1460,12 @@ void WasmCodeManager::FreeNativeModule(Vector owned_code_space, + TRACE_HEAP("VMem Release: 0x%" PRIxPTR ":0x%" PRIxPTR " (%zu)\n", + code_space.address(), code_space.end(), code_space.size()); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + if (CanRegisterUnwindInfoForNonABICompliantCodeRange()) { + win64_unwindinfo::UnregisterNonABICompliantCodeRange( + reinterpret_cast(code_space.address())); + } +-#endif ++#endif // V8_OS_WIN64 + + lookup_map_.erase(code_space.address()); + memory_tracker_->ReleaseReservation(code_space.size()); +diff --git a/src/wasm/wasm-code-manager.h b/src/wasm/wasm-code-manager.h +index 49c287df2c8efa718e2599206e069c26fc03b255..1fd00743996acae7b6c84517baa512e15bc32386 100644 +--- a/src/wasm/wasm-code-manager.h ++++ b/src/wasm/wasm-code-manager.h +@@ -605,9 +605,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { + } + #endif + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + bool CanRegisterUnwindInfoForNonABICompliantCodeRange() const; +-#endif ++#endif // V8_OS_WIN64 + + NativeModule* LookupNativeModule(Address pc) const; + WasmCode* LookupCode(Address pc) const; +@@ -617,11 +617,11 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { + + void SetMaxCommittedMemoryForTesting(size_t limit); + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + void DisableWin64UnwindInfoForTesting() { + is_win64_unwind_info_disabled_for_testing_ = true; + } +-#endif ++#endif // V8_OS_WIN64 + + static size_t EstimateNativeModuleCodeSize(const WasmModule* module); + static size_t EstimateNativeModuleNonCodeSize(const WasmModule* module); +@@ -649,9 +649,9 @@ class V8_EXPORT_PRIVATE WasmCodeManager final { + + size_t max_committed_code_space_; + +-#if defined(V8_OS_WIN_X64) ++#if defined(V8_OS_WIN64) + bool is_win64_unwind_info_disabled_for_testing_; +-#endif ++#endif // V8_OS_WIN64 + + std::atomic total_committed_code_space_; + // If the committed code space exceeds {critical_committed_code_space_}, then +diff --git a/test/cctest/BUILD.gn b/test/cctest/BUILD.gn +index 42396087eedd844b07f8ca842ce1a0c17d8a94f7..f2d5693793da6d45593b3f18712e959fcac8eecf 100644 +--- a/test/cctest/BUILD.gn ++++ b/test/cctest/BUILD.gn +@@ -310,6 +310,9 @@ v8_source_set("cctest_sources") { + "test-utils-arm64.cc", + "test-utils-arm64.h", + ] ++ if (is_win) { ++ sources += [ "test-stack-unwinding-win64.cc" ] ++ } + } else if (v8_current_cpu == "x86") { + sources += [ ### gcmole(arch:ia32) ### + "test-assembler-ia32.cc", +@@ -348,7 +351,7 @@ v8_source_set("cctest_sources") { + "test-macro-assembler-x64.cc", + ] + if (is_win) { +- sources += [ "test-stack-unwinding-x64.cc" ] ++ sources += [ "test-stack-unwinding-win64.cc" ] + } + } else if (v8_current_cpu == "ppc" || v8_current_cpu == "ppc64") { + sources += [ ### gcmole(arch:ppc) ### +diff --git a/test/cctest/test-stack-unwinding-x64.cc b/test/cctest/test-stack-unwinding-win64.cc +similarity index 76% +rename from test/cctest/test-stack-unwinding-x64.cc +rename to test/cctest/test-stack-unwinding-win64.cc +index 583e14111ad676cf7cb9984407ca9cd0bf9f5f7c..84f1318a29525ae5c71275ecaa6096dfaabcc90c 100644 +--- a/test/cctest/test-stack-unwinding-x64.cc ++++ b/test/cctest/test-stack-unwinding-win64.cc +@@ -6,9 +6,15 @@ + #include "src/init/v8.h" + #include "test/cctest/cctest.h" + +-class UnwindingWinX64Callbacks { ++#if defined(V8_OS_WIN_X64) ++#define CONTEXT_PC(context) (context.Rip) ++#elif defined(V8_OS_WIN_ARM64) ++#define CONTEXT_PC(context) (context.Pc) ++#endif ++ ++class UnwindingWin64Callbacks { + public: +- UnwindingWinX64Callbacks() = default; ++ UnwindingWin64Callbacks() = default; + + static void Getter(v8::Local name, + const v8::PropertyCallbackInfo& info) { +@@ -31,25 +37,26 @@ class UnwindingWinX64Callbacks { + int iframe = 0; + while (++iframe < max_frames) { + uint64_t image_base; +- PRUNTIME_FUNCTION function_entry = +- ::RtlLookupFunctionEntry(context_record.Rip, &image_base, nullptr); ++ PRUNTIME_FUNCTION function_entry = ::RtlLookupFunctionEntry( ++ CONTEXT_PC(context_record), &image_base, nullptr); + if (!function_entry) break; + + void* handler_data; + uint64_t establisher_frame; +- ::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, context_record.Rip, +- function_entry, &context_record, &handler_data, +- &establisher_frame, NULL); ++ ::RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, ++ CONTEXT_PC(context_record), function_entry, ++ &context_record, &handler_data, &establisher_frame, ++ NULL); + } + return iframe; + } + }; + +-// Verifies that stack unwinding data has been correctly registered on Win/x64. +-UNINITIALIZED_TEST(StackUnwindingWinX64) { ++// Verifies that stack unwinding data has been correctly registered on Win64. ++UNINITIALIZED_TEST(StackUnwindingWin64) { + #ifdef V8_WIN64_UNWINDING_INFO + +- static const char* unwinding_win_x64_test_source = ++ static const char* unwinding_win64_test_source = + "function start(count) {\n" + " for (var i = 0; i < count; i++) {\n" + " var o = instance.foo;\n" +@@ -79,18 +86,18 @@ UNINITIALIZED_TEST(StackUnwindingWinX64) { + v8::Local instance_template = + func_template->InstanceTemplate(); + +- UnwindingWinX64Callbacks accessors; ++ UnwindingWin64Callbacks accessors; + v8::Local data = v8::External::New(isolate, &accessors); + instance_template->SetAccessor(v8_str("foo"), +- &UnwindingWinX64Callbacks::Getter, +- &UnwindingWinX64Callbacks::Setter, data); ++ &UnwindingWin64Callbacks::Getter, ++ &UnwindingWin64Callbacks::Setter, data); + v8::Local func = + func_template->GetFunction(env.local()).ToLocalChecked(); + v8::Local instance = + func->NewInstance(env.local()).ToLocalChecked(); + env->Global()->Set(env.local(), v8_str("instance"), instance).FromJust(); + +- CompileRun(unwinding_win_x64_test_source); ++ CompileRun(unwinding_win64_test_source); + v8::Local function = v8::Local::Cast( + env->Global()->Get(env.local(), v8_str("start")).ToLocalChecked()); + +@@ -106,3 +113,5 @@ UNINITIALIZED_TEST(StackUnwindingWinX64) { + + #endif // V8_WIN64_UNWINDING_INFO + } ++ ++#undef CONTEXT_PC From 01ad7345cf63109bdd329a8ba086a743255a5439 Mon Sep 17 00:00:00 2001 From: Richard Townsend Date: Tue, 23 Jul 2019 15:45:05 +0100 Subject: [PATCH 2/8] feat: backport crashpad cpu capture context Backport of [1] (originally written by @kaadam) to Chromium 76's crashpad. This lets you see the register values within the crash dump. [1] https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1632749 --- patches/common/chromium/.patches | 1 + ...ackport_crashpad_cpu_context_capture.patch | 199 ++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 patches/common/chromium/backport_crashpad_cpu_context_capture.patch diff --git a/patches/common/chromium/.patches b/patches/common/chromium/.patches index 37b3dc43a75ab..44ba3154d2294 100644 --- a/patches/common/chromium/.patches +++ b/patches/common/chromium/.patches @@ -81,4 +81,5 @@ cross_site_document_resource_handler.patch frame_host_manager.patch crashpad_pid_check.patch fix_use_weakptr_to_detect_deletion.patch +backport_crashpad_cpu_context_capture.patch fix_disabling_compositor_recycling.patch diff --git a/patches/common/chromium/backport_crashpad_cpu_context_capture.patch b/patches/common/chromium/backport_crashpad_cpu_context_capture.patch new file mode 100644 index 0000000000000..c3bec7c8355ff --- /dev/null +++ b/patches/common/chromium/backport_crashpad_cpu_context_capture.patch @@ -0,0 +1,199 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Richard Townsend +Date: Tue, 23 Jul 2019 15:36:43 +0100 +Subject: feat: backport crashpad CPU context capture + +Backport of [1] for Windows on Arm (originally writen by @kaadam). +This allows you to see register values within the crash report. + +[1] https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1632749 + +diff --git a/third_party/crashpad/crashpad/handler/BUILD.gn b/third_party/crashpad/crashpad/handler/BUILD.gn +index dc32b94e651c906f9ab1868165448805c71fe258..67c77e5fbc131d789b77dcca215f507027fd1fd0 100644 +--- a/third_party/crashpad/crashpad/handler/BUILD.gn ++++ b/third_party/crashpad/crashpad/handler/BUILD.gn +@@ -180,8 +180,6 @@ if (crashpad_is_android) { + if (crashpad_is_in_chromium) { + no_default_deps = true + } +- remove_configs = +- [ "//build/config/android:default_orderfile_instrumentation" ] + } + } + +diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn +index 620ae2550a0ba81fb9ad903d570d5ddbb8915b79..088a7b59a4e34bb5489ab34a0ac928f706efc8d3 100644 +--- a/third_party/crashpad/crashpad/util/BUILD.gn ++++ b/third_party/crashpad/crashpad/util/BUILD.gn +@@ -396,8 +396,17 @@ static_library("util") { + "win/safe_terminate_process.asm", + ] + } else { +- # TODO: Add assembly code of CaptureContext for Windows ARM64. +- sources += [ "misc/capture_context_broken.cc" ] ++ # Most Crashpad builds use Microsoft's armasm64.exe macro assembler for ++ # .asm source files. When building in Chromium, clang-cl is used as the ++ # assembler instead. Since the two assemblers recognize different ++ # assembly dialects, the same .asm file can't be used for each. As a ++ # workaround, use a prebuilt .obj file when the Microsoft-dialect ++ # assembler isn't available. ++ if (crashpad_is_in_chromium) { ++ sources += [ "misc/capture_context_win_arm64.obj" ] ++ } else { ++ sources += [ "misc/capture_context_win_arm64.asm" ] ++ } + } + } else { + sources += [ +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S b/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S +index 21aefad0b1ed0e05112060e427bbef8fd86dfee2..0ebc7f7fe8ca159268bec6dd34c2e043bc1cfc63 100644 +--- a/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S ++++ b/third_party/crashpad/crashpad/util/misc/capture_context_fuchsia.S +@@ -116,7 +116,7 @@ CAPTURECONTEXT_SYMBOL: + movq 0x90(%rdi), %rax + movq 0x28(%rdi), %r8 + +- // TODO(scottmg): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + popfq + +@@ -166,7 +166,7 @@ CAPTURECONTEXT_SYMBOL: + // Restore x1 from the saved context. + ldr x1, [x0, #0xc0] + +- // TODO(scottmg): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + ret + +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_linux.S b/third_party/crashpad/crashpad/util/misc/capture_context_linux.S +index 657a979a76ea1cfc02633e8553d41005fd1a2749..de71e7231273ac2a79b3eebfde2357e3eda9f94d 100644 +--- a/third_party/crashpad/crashpad/util/misc/capture_context_linux.S ++++ b/third_party/crashpad/crashpad/util/misc/capture_context_linux.S +@@ -282,7 +282,7 @@ CAPTURECONTEXT_SYMBOL2: + // Restore r1. + ldr r1, [r0, #0x24] + +- // TODO(jperaza): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + mov PC, LR + +@@ -326,7 +326,7 @@ CAPTURECONTEXT_SYMBOL2: + // Restore x1 from the saved context. + ldr x1, [x0, #0xc0] + +- // TODO(jperaza): save floating-point registers. ++ // TODO(https://crashpad.chromium.org/bug/300): save floating-point registers. + + ret + #elif defined(__mips__) +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.asm b/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.asm +new file mode 100644 +index 0000000000000000000000000000000000000000..5630698f8d8ef198eb9f8cf28692eeaf97a961a5 +--- /dev/null ++++ b/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.asm +@@ -0,0 +1,64 @@ ++; Copyright 2019 The Crashpad Authors. All rights reserved. ++; ++; Licensed under the Apache License, Version 2.0 (the "License"); ++; you may not use this file except in compliance with the License. ++; You may obtain a copy of the License at ++; ++; http://www.apache.org/licenses/LICENSE-2.0 ++; ++; Unless required by applicable law or agreed to in writing, software ++; distributed under the License is distributed on an "AS IS" BASIS, ++; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++; See the License for the specific language governing permissions and ++; limitations under the License. ++ ++ EXPORT |?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z| ++ AREA |.text|, CODE ++|?CaptureContext@crashpad@@YAXPEAU_CONTEXT@@@Z| PROC ++ ; Save general purpose registers in context.regs[i]. ++ ; The original x0 can't be recovered. ++ stp x0, x1, [x0, #0x008] ++ stp x2, x3, [x0, #0x018] ++ stp x4, x5, [x0, #0x028] ++ stp x6, x7, [x0, #0x038] ++ stp x8, x9, [x0, #0x048] ++ stp x10, x11, [x0, #0x058] ++ stp x12, x13, [x0, #0x068] ++ stp x14, x15, [x0, #0x078] ++ stp x16, x17, [x0, #0x088] ++ stp x18, x19, [x0, #0x098] ++ stp x20, x21, [x0, #0x0a8] ++ stp x22, x23, [x0, #0x0b8] ++ stp x24, x25, [x0, #0x0c8] ++ stp x26, x27, [x0, #0x0d8] ++ stp x28, x29, [x0, #0x0e8] ++ ++ ; The original LR can't be recovered. ++ str LR, [x0, #0x0f8] ++ ++ ; Use x1 as a scratch register. ++ mov x1, SP ++ str x1, [x0, #0x100] ; context.sp ++ ++ ; The link register holds the return address for this function. ++ str LR, [x0, #0x108] ; context.pc ++ ++ ; pstate should hold SPSR but NZCV are the only bits we know about. ++ mrs x1, NZCV ++ ++ ; Enable Control flags, such as CONTEXT_ARM64, CONTEXT_CONTROL, ++ ; CONTEXT_INTEGER ++ ldr w1, =0x00400003 ++ ++ ; Set ControlFlags /0x000/ and pstate /0x004/ at the same time. ++ str x1, [x0, #0x000] ++ ++ ; Restore x1 from the saved context. ++ ldr x1, [x0, #0x010] ++ ++ ; TODO(https://crashpad.chromium.org/bug/300): save floating-point registers ++ ++ ret ++ ENDP ++ ++ END +diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.obj b/third_party/crashpad/crashpad/util/misc/capture_context_win_arm64.obj +new file mode 100644 +index 0000000000000000000000000000000000000000..11c76a1aae15f8331d37063a3adc5e6ad37fcc8f +GIT binary patch +literal 614 +zcmYdU#l-MIOFuS-k%57S0Rr?&QY%WJY!H5C@9`=<2M>tjro#9+5a)oQ9 +z*d6Yb5>I$mO1EC^;s%D6u%BATb5OC@sm%iOJ0@2FfKCl#~{w +z#wX|Jfjk{wo|zY)Sd?pKqL-hP#lT?0U?a%P#K7dqF$gfs$Yf;j%}g%JFV0UZ +zQP2p|RB#OPRq#y&iYPc17pLYX<)jt?RXZf-=N9N?rp(A>X8ix3fdS~wwA92BJp%&) +zpe#g0FD)}C6=F2QKcJd)7K&V*Sey$ri~%_ofuY5~%m|7{RDc|VKyL!ofZ`AnfI=4p +sK;|$p7y(IpXGq97LjukL7RU|`k&Y1ou8yJc&i;NOt`Q*)4h~Ta0HmRmk^lez + +literal 0 +HcmV?d00001 + +diff --git a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc +index e89b8ff675bed2fa65263ea451d40995e0b010b7..2593ff2de0327c393c30cae9962a329c5e27b64e 100644 +--- a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc ++++ b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc +@@ -448,16 +448,9 @@ bool ExceptionHandlerServer::ServiceClientConnection( + DWORD real_pid = 0; + if (get_named_pipe_client_process_id(service_context.pipe(), &real_pid) && + message.registration.client_process_id != real_pid) { +- // Electron: When both browser process and renderer process are connecting +- // to the pipe, the API may return the PID of browser process as real_pid, +- // which is different from the PID of renderer process. +- // +- // I don't understand why Chromium does not have this issue. +-#if 0 + LOG(ERROR) << "forged client pid, real pid: " << real_pid + << ", got: " << message.registration.client_process_id; + return false; +-#endif + } + } + From a2b8d73eff50b980f6f4472e3b768874857f758c Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Thu, 1 Aug 2019 13:25:54 -0700 Subject: [PATCH 3/8] build: make win on arm patches only apply for win on arm builds --- DEPS | 13 +++++++++++++ patches/win_arm64/chromium/.patches | 1 + .../backport_crashpad_cpu_context_capture.patch | 0 patches/win_arm64/config.json | 5 +++++ patches/win_arm64/v8/.patches | 1 + ...nwind_v8_frames_correctly_on_windows_arm64.patch | 0 6 files changed, 20 insertions(+) create mode 100644 patches/win_arm64/chromium/.patches rename patches/{common => win_arm64}/chromium/backport_crashpad_cpu_context_capture.patch (100%) create mode 100644 patches/win_arm64/config.json create mode 100644 patches/win_arm64/v8/.patches rename patches/{common => win_arm64}/v8/unwind_v8_frames_correctly_on_windows_arm64.patch (100%) diff --git a/DEPS b/DEPS index 67e2593db1217..d7a65aac38883 100644 --- a/DEPS +++ b/DEPS @@ -31,6 +31,9 @@ vars = { # To be able to build clean Chromium from sources. 'apply_patches': True, + # Apply the patches specific to windows on arm64 + 'apply_win_arm64_patches': False, + # Python interface to Amazon Web Services. Is used for releases only. 'checkout_boto': False, @@ -96,6 +99,16 @@ hooks = [ 'src/electron/patches/common/config.json', ], }, + { + 'name': 'patch_chromium', + 'condition': 'checkout_chromium and apply_patches and apply_win_arm64_patches', + 'pattern': 'src/electron', + 'action': [ + 'python', + 'src/electron/script/apply_all_patches.py', + 'src/electron/patches/win_arm64/config.json', + ], + }, { 'name': 'electron_external_binaries', 'pattern': 'src/electron/script/update-external-binaries.py', diff --git a/patches/win_arm64/chromium/.patches b/patches/win_arm64/chromium/.patches new file mode 100644 index 0000000000000..660ef2a0b5818 --- /dev/null +++ b/patches/win_arm64/chromium/.patches @@ -0,0 +1 @@ +backport_crashpad_cpu_context_capture.patch diff --git a/patches/common/chromium/backport_crashpad_cpu_context_capture.patch b/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch similarity index 100% rename from patches/common/chromium/backport_crashpad_cpu_context_capture.patch rename to patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch diff --git a/patches/win_arm64/config.json b/patches/win_arm64/config.json new file mode 100644 index 0000000000000..7b12f53fb9f58 --- /dev/null +++ b/patches/win_arm64/config.json @@ -0,0 +1,5 @@ +{ + "src/electron/patches/win_arm64/chromium": "src", + + "src/electron/patches/win_arm64/v8": "src/v8" +} diff --git a/patches/win_arm64/v8/.patches b/patches/win_arm64/v8/.patches new file mode 100644 index 0000000000000..98a5d5620f072 --- /dev/null +++ b/patches/win_arm64/v8/.patches @@ -0,0 +1 @@ +unwind_v8_frames_correctly_on_windows_arm64.patch diff --git a/patches/common/v8/unwind_v8_frames_correctly_on_windows_arm64.patch b/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch similarity index 100% rename from patches/common/v8/unwind_v8_frames_correctly_on_windows_arm64.patch rename to patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch From c3128148851c61159007a8233921a8e9a568778c Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Thu, 1 Aug 2019 13:53:53 -0700 Subject: [PATCH 4/8] Update .patches --- patches/common/chromium/.patches | 1 - 1 file changed, 1 deletion(-) diff --git a/patches/common/chromium/.patches b/patches/common/chromium/.patches index 44ba3154d2294..37b3dc43a75ab 100644 --- a/patches/common/chromium/.patches +++ b/patches/common/chromium/.patches @@ -81,5 +81,4 @@ cross_site_document_resource_handler.patch frame_host_manager.patch crashpad_pid_check.patch fix_use_weakptr_to_detect_deletion.patch -backport_crashpad_cpu_context_capture.patch fix_disabling_compositor_recycling.patch From 02cfc0c6258b41626bf85369bfee99299df526f8 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Thu, 1 Aug 2019 13:54:09 -0700 Subject: [PATCH 5/8] Update .patches --- patches/common/v8/.patches | 1 - 1 file changed, 1 deletion(-) diff --git a/patches/common/v8/.patches b/patches/common/v8/.patches index 6426e8b225a2a..13d69fdada3c6 100644 --- a/patches/common/v8/.patches +++ b/patches/common/v8/.patches @@ -6,4 +6,3 @@ dcheck.patch export_symbols_needed_for_windows_build.patch workaround_an_undefined_symbol_error.patch do_not_export_private_v8_symbols_on_windows.patch -unwind_v8_frames_correctly_on_windows_arm64.patch From 2a3dac2ef54e2c9f35c1b6f332413a8a5e86c91a Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Thu, 1 Aug 2019 17:20:13 -0700 Subject: [PATCH 6/8] Update DEPS --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index d7a65aac38883..d9d9a9f27e83a 100644 --- a/DEPS +++ b/DEPS @@ -101,7 +101,7 @@ hooks = [ }, { 'name': 'patch_chromium', - 'condition': 'checkout_chromium and apply_patches and apply_win_arm64_patches', + 'condition': '(checkout_chromium and apply_patches) and apply_win_arm64_patches', 'pattern': 'src/electron', 'action': [ 'python', From 54fdc5d6e3f86d6cd5401d43cad5234cb577a4d0 Mon Sep 17 00:00:00 2001 From: Richard Townsend Date: Thu, 8 Aug 2019 11:52:36 +0100 Subject: [PATCH 7/8] fix: update the patch to the as-landed version --- ...v8_frames_correctly_on_windows_arm64.patch | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch b/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch index 8480dc2ed028f..12778a2dc42c8 100644 --- a/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch +++ b/patches/win_arm64/v8/unwind_v8_frames_correctly_on_windows_arm64.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Tom Tan -Date: Tue, 23 Jul 2019 00:02:23 -0700 +Date: Fri, 26 Jul 2019 23:36:52 -0700 Subject: Unwind V8 frames correctly on Windows ARM64 On Windows ARM64, OS stack walking does not work because the V8 ARM64 backend @@ -36,6 +36,11 @@ to maintain for Windows ARM64 which was released since 1709 windows build. Bug: chromium:893460 Change-Id: Ic74cbdad8af5cf342185030a4c53796f12ea5429 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1701133 +Reviewed-by: Michael Starzinger +Reviewed-by: Jakob Gruber +Commit-Queue: Jakob Gruber +Cr-Commit-Position: refs/heads/master@{#63002} diff --git a/BUILD.gn b/BUILD.gn index 071a85c3f57ae92dcf90d47a13299e43f81753ec..d3cc60935541d080234ebc30b231904a48e68862 100644 @@ -64,7 +69,7 @@ index 071a85c3f57ae92dcf90d47a13299e43f81753ec..d3cc60935541d080234ebc30b231904a # TODO(mostynb@vewd.com): fix this code so it doesn't need # to be excluded, see the comments inside. diff --git a/src/api/api.cc b/src/api/api.cc -index 6117189ad11a189e03c4db1307d919b818751b18..41a7fefec2c1ec6af55a81f2298ab6a43b76b4bb 100644 +index 6117189ad11a189e03c4db1307d919b818751b18..5b8f980929b21305f6846e8e6a3342926251efbf 100644 --- a/src/api/api.cc +++ b/src/api/api.cc @@ -121,9 +121,9 @@ @@ -90,7 +95,7 @@ index 6117189ad11a189e03c4db1307d919b818751b18..41a7fefec2c1ec6af55a81f2298ab6a4 #else - // Not implemented on ARM64. -#endif -+ // Not implemented. ++ // Not implemented, port needed. +#endif // V8_OS_WIN64 } -#endif @@ -99,7 +104,7 @@ index 6117189ad11a189e03c4db1307d919b818751b18..41a7fefec2c1ec6af55a81f2298ab6a4 void v8::V8::SetEntropySource(EntropySource entropy_source) { base::RandomNumberGenerator::SetEntropySource(entropy_source); diff --git a/src/builtins/arm64/builtins-arm64.cc b/src/builtins/arm64/builtins-arm64.cc -index f81a1955eeb474c527f25f9e59edb0522e81824b..560e53a61c65086744b817a3fb5f32ee1f82dbd7 100644 +index f81a1955eeb474c527f25f9e59edb0522e81824b..0619fbfe55e0efad72ae5f2cb9623285025cacb2 100644 --- a/src/builtins/arm64/builtins-arm64.cc +++ b/src/builtins/arm64/builtins-arm64.cc @@ -24,6 +24,10 @@ @@ -118,7 +123,7 @@ index f81a1955eeb474c527f25f9e59edb0522e81824b..560e53a61c65086744b817a3fb5f32ee __ EnableInstrumentation(); +#if defined(V8_OS_WIN) -+ // Windows ARM64 relies on frame pointer (fp/x29 which are aliases to each ++ // Windows ARM64 relies on a frame pointer (fp/x29 which are aliases to each + // other) chain to do stack unwinding, but JSEntry breaks that by setting fp + // to point to bad_frame_pointer below. To fix unwind information for this + // case, JSEntry registers the offset (from current fp to the caller's fp @@ -798,7 +803,7 @@ index 8fb01dba9a55c75de677286baa19bb9edae74231..6cc53da51f16a45c3a8ad14ca0b2150b - -#endif // defined(V8_OS_WIN_X64) diff --git a/src/diagnostics/unwinding-info-win64.h b/src/diagnostics/unwinding-info-win64.h -index f6611e7e2ec5a8afc1769886593f112eb4ad0f89..12092cc06a77aca9a63d01731750e1a24cf13980 100644 +index f6611e7e2ec5a8afc1769886593f112eb4ad0f89..8f8c9469ebf92c1f81af8364486cd45f4778b248 100644 --- a/src/diagnostics/unwinding-info-win64.h +++ b/src/diagnostics/unwinding-info-win64.h @@ -9,7 +9,7 @@ @@ -819,7 +824,7 @@ index f6611e7e2ec5a8afc1769886593f112eb4ad0f89..12092cc06a77aca9a63d01731750e1a2 -static const int kRbpPrefixCodes = 2; -static const int kRbpPrefixLength = - kPushRbpInstructionLength + kMovRbpRspInstructionLength; -+static constexpr int kOSPageSize = 4096; ++static const int kOSPageSize = 4096; /** * Returns true if V8 is configured to emit unwinding data for embedded in the @@ -839,7 +844,7 @@ index f6611e7e2ec5a8afc1769886593f112eb4ad0f89..12092cc06a77aca9a63d01731750e1a2 + * to cover the whole code range of an isolate or WASM module. The extra + * RUNTIME_FUNCTIONs are assumed following the first one in the reserved page. + */ -+static constexpr uint32_t kDefaultRuntimeFunctionCount = 1; ++static const uint32_t kDefaultRuntimeFunctionCount = 1; + +#if defined(V8_OS_WIN_X64) + @@ -886,7 +891,7 @@ index f6611e7e2ec5a8afc1769886593f112eb4ad0f89..12092cc06a77aca9a63d01731750e1a2 + * length, besides 2 LSB which are always 0. + * https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#xdata-records + */ -+static constexpr int kMaxFunctionLength = ((1 << 18) - 1) << 2; ++static const int kMaxFunctionLength = ((1 << 18) - 1) << 2; + +/** + * Returns a vector of bytes that contains the Win ARM64 unwind data used for From 3a1b8e764bcbe25dbfccd07c3b7bf2860febcdf7 Mon Sep 17 00:00:00 2001 From: Richard Townsend Date: Thu, 8 Aug 2019 18:28:14 +0100 Subject: [PATCH 8/8] fix: remove accidental revert of crashpad_pid_check.patch --- ...ackport_crashpad_cpu_context_capture.patch | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch b/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch index c3bec7c8355ff..794973f25e17b 100644 --- a/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch +++ b/patches/win_arm64/chromium/backport_crashpad_cpu_context_capture.patch @@ -176,24 +176,3 @@ sK;|$p7y(IpXGq97LjukL7RU|`k&Y1ou8yJc&i;NOt`Q*)4h~Ta0HmRmk^lez literal 0 HcmV?d00001 -diff --git a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc -index e89b8ff675bed2fa65263ea451d40995e0b010b7..2593ff2de0327c393c30cae9962a329c5e27b64e 100644 ---- a/third_party/crashpad/crashpad/util/win/exception_handler_server.cc -+++ b/third_party/crashpad/crashpad/util/win/exception_handler_server.cc -@@ -448,16 +448,9 @@ bool ExceptionHandlerServer::ServiceClientConnection( - DWORD real_pid = 0; - if (get_named_pipe_client_process_id(service_context.pipe(), &real_pid) && - message.registration.client_process_id != real_pid) { -- // Electron: When both browser process and renderer process are connecting -- // to the pipe, the API may return the PID of browser process as real_pid, -- // which is different from the PID of renderer process. -- // -- // I don't understand why Chromium does not have this issue. --#if 0 - LOG(ERROR) << "forged client pid, real pid: " << real_pid - << ", got: " << message.registration.client_process_id; - return false; --#endif - } - } -