Commit 876618fb authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[mksnapshot] Hide the win64 unwinding info writer

The win64-specific unwinding info writer should not be part of the
generic EmbeddedFileWriter class. Let's hide it in the platform-specific
writer.

Bug: v8:9103
Change-Id: Ifc4f8b326f07e037b6876e0592cb70b8281edb9a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627536
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Auto-Submit: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61850}
parent a335f2ae
......@@ -9,10 +9,6 @@
#include "src/codegen/source-position-table.h"
#include "src/objects/code-inl.h"
// TODO(jgruber): Refactor to move windows-specific code into the
// windows-specific file writer.
#include "src/snapshot/embedded/platform-embedded-file-writer-win.h"
namespace v8 {
namespace internal {
......@@ -97,8 +93,14 @@ void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
}
#if defined(V8_OS_WIN_X64)
if (win64_unwindinfo::CanEmitUnwindInfoForBuiltins()) {
WriteUnwindInfo(w, blob);
{
i::EmbeddedVector<char, kTemporaryStringLength> unwind_info_symbol;
i::SNPrintF(unwind_info_symbol, "%s_Builtins_UnwindInfo",
embedded_variant_);
w->MaybeEmitUnwindData(unwind_info_symbol.begin(),
EmbeddedBlobDataSymbol().c_str(), blob,
reinterpret_cast<const void*>(&unwind_infos_[0]));
}
#endif
......@@ -270,123 +272,5 @@ void EmbeddedFileWriter::PrepareBuiltinSourcePositionMap(Builtins* builtins) {
}
}
#if defined(V8_OS_WIN_X64)
std::string EmbeddedFileWriter::BuiltinsUnwindInfoLabel() const {
i::EmbeddedVector<char, kTemporaryStringLength> embedded_blob_data_symbol;
i::SNPrintF(embedded_blob_data_symbol, "%s_Builtins_UnwindInfo",
embedded_variant_);
return std::string{embedded_blob_data_symbol.begin()};
}
void EmbeddedFileWriter::SetBuiltinUnwindData(
int builtin_index, const win64_unwindinfo::BuiltinUnwindInfo& unwind_info) {
DCHECK_LT(builtin_index, Builtins::builtin_count);
unwind_infos_[builtin_index] = unwind_info;
}
void EmbeddedFileWriter::WriteUnwindInfoEntry(PlatformEmbeddedFileWriterBase* w,
uint64_t rva_start,
uint64_t rva_end) const {
PlatformEmbeddedFileWriterWin* w_win =
static_cast<PlatformEmbeddedFileWriterWin*>(w);
w_win->DeclareRvaToSymbol(EmbeddedBlobDataSymbol().c_str(), rva_start);
w_win->DeclareRvaToSymbol(EmbeddedBlobDataSymbol().c_str(), rva_end);
w_win->DeclareRvaToSymbol(BuiltinsUnwindInfoLabel().c_str());
}
void EmbeddedFileWriter::WriteUnwindInfo(PlatformEmbeddedFileWriterBase* w,
const i::EmbeddedData* blob) const {
PlatformEmbeddedFileWriterWin* w_win =
static_cast<PlatformEmbeddedFileWriterWin*>(w);
// Emit an UNWIND_INFO (XDATA) struct, which contains the unwinding
// information that is used for all builtin functions.
DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
w_win->Comment("xdata for all the code in the embedded blob.");
w_win->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
w_win->StartXdataSection();
{
w_win->DeclareLabel(BuiltinsUnwindInfoLabel().c_str());
std::vector<uint8_t> xdata =
win64_unwindinfo::GetUnwindInfoForBuiltinFunctions();
WriteBinaryContentsAsInlineAssembly(w_win, xdata.data(),
static_cast<uint32_t>(xdata.size()));
w_win->Comment(" ExceptionHandler");
w_win->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
}
w_win->EndXdataSection();
w_win->Newline();
// Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as
// documented here:
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
w_win->Comment(
"pdata for all the code in the embedded blob (structs of type "
"RUNTIME_FUNCTION).");
w_win->Comment(" BeginAddress");
w_win->Comment(" EndAddress");
w_win->Comment(" UnwindInfoAddress");
w_win->StartPdataSection();
{
Address prev_builtin_end_offset = 0;
for (int i = 0; i < Builtins::builtin_count; i++) {
// Some builtins are leaf functions from the point of view of Win64 stack
// walking: they do not move the stack pointer and do not require a PDATA
// entry because the return address can be retrieved from [rsp].
if (!blob->ContainsBuiltin(i)) continue;
if (unwind_infos_[i].is_leaf_function()) continue;
uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) -
reinterpret_cast<Address>(blob->data());
uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i);
const std::vector<int>& xdata_desc = unwind_infos_[i].fp_offsets();
if (xdata_desc.empty()) {
// Some builtins do not have any "push rbp - mov rbp, rsp" instructions
// to start a stack frame. We still emit a PDATA entry as if they had,
// relying on the fact that we can find the previous frame address from
// rbp in most cases. Note that since the function does not really start
// with a 'push rbp' we need to specify the start RVA in the PDATA entry
// a few bytes before the beginning of the function, if it does not
// overlap the end of the previous builtin.
WriteUnwindInfoEntry(
w_win,
std::max(prev_builtin_end_offset,
builtin_start_offset - win64_unwindinfo::kRbpPrefixLength),
builtin_start_offset + builtin_size);
} else {
// Some builtins have one or more "push rbp - mov rbp, rsp" sequences,
// but not necessarily at the beginning of the function. In this case
// we want to yield a PDATA entry for each block of instructions that
// emit an rbp frame. If the function does not start with 'push rbp'
// we also emit a PDATA entry for the initial block of code up to the
// first 'push rbp', like in the case above.
if (xdata_desc[0] > 0) {
WriteUnwindInfoEntry(w_win,
std::max(prev_builtin_end_offset,
builtin_start_offset -
win64_unwindinfo::kRbpPrefixLength),
builtin_start_offset + xdata_desc[0]);
}
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;
WriteUnwindInfoEntry(w_win, builtin_start_offset + chunk_start,
builtin_start_offset + chunk_end);
}
}
prev_builtin_end_offset = builtin_start_offset + builtin_size;
w_win->Newline();
}
}
w_win->EndPdataSection();
w_win->Newline();
}
#endif
} // namespace internal
} // namespace v8
......@@ -62,7 +62,10 @@ class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
#if defined(V8_OS_WIN_X64)
void SetBuiltinUnwindData(
int builtin_index,
const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override;
const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override {
DCHECK_LT(builtin_index, Builtins::builtin_count);
unwind_infos_[builtin_index] = unwinding_info;
}
#endif
void SetEmbeddedFile(const char* embedded_src_path) {
......
......@@ -12,6 +12,8 @@
namespace v8 {
namespace internal {
class EmbeddedData;
enum DataDirective {
kByte,
kLong,
......@@ -75,6 +77,16 @@ class PlatformEmbeddedFileWriterBase {
virtual int IndentedDataDirective(DataDirective directive) = 0;
// This awkward interface works around the fact that unwind data emission
// is both high-level and platform-dependent. The former implies it should
// live in EmbeddedFileWriter, but code there should be platform-independent.
//
// Emits unwinding data on x64 Windows, and does nothing otherwise.
virtual void MaybeEmitUnwindData(const char* unwind_info_symbol,
const char* embedded_blob_data_symbol,
const EmbeddedData* blob,
const void* unwind_infos) {}
protected:
FILE* fp_ = nullptr;
};
......
......@@ -6,6 +6,14 @@
#include <algorithm>
#include "src/common/globals.h" // For V8_OS_WIN_X64.
#if defined(V8_OS_WIN_X64)
#include "src/builtins/builtins.h"
#include "src/diagnostics/unwinding-info-win64.h"
#include "src/snapshot/embedded/embedded-data.h"
#endif
namespace v8 {
namespace internal {
......@@ -93,8 +101,134 @@ const char* DirectiveAsString(DataDirective directive) {
#endif
}
#if defined(V8_OS_WIN_X64)
void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterWin* w,
const char* unwind_info_symbol,
const char* embedded_blob_data_symbol,
uint64_t rva_start, uint64_t rva_end) {
w->DeclareRvaToSymbol(embedded_blob_data_symbol, rva_start);
w->DeclareRvaToSymbol(embedded_blob_data_symbol, rva_end);
w->DeclareRvaToSymbol(unwind_info_symbol);
}
void EmitUnwindData(PlatformEmbeddedFileWriterWin* w,
const char* unwind_info_symbol,
const char* embedded_blob_data_symbol,
const EmbeddedData* blob,
const win64_unwindinfo::BuiltinUnwindInfo* unwind_infos) {
// Emit an UNWIND_INFO (XDATA) struct, which contains the unwinding
// information that is used for all builtin functions.
DCHECK(win64_unwindinfo::CanEmitUnwindInfoForBuiltins());
w->Comment("xdata for all the code in the embedded blob.");
w->DeclareExternalFunction(CRASH_HANDLER_FUNCTION_NAME_STRING);
w->StartXdataSection();
{
w->DeclareLabel(unwind_info_symbol);
std::vector<uint8_t> xdata =
win64_unwindinfo::GetUnwindInfoForBuiltinFunctions();
DCHECK(!xdata.empty());
w->IndentedDataDirective(kByte);
for (size_t i = 0; i < xdata.size(); i++) {
if (i > 0) fprintf(w->fp(), ",");
w->HexLiteral(xdata[i]);
}
w->Newline();
w->Comment(" ExceptionHandler");
w->DeclareRvaToSymbol(CRASH_HANDLER_FUNCTION_NAME_STRING);
}
w->EndXdataSection();
w->Newline();
// Emit a RUNTIME_FUNCTION (PDATA) entry for each builtin function, as
// documented here:
// https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
w->Comment(
"pdata for all the code in the embedded blob (structs of type "
"RUNTIME_FUNCTION).");
w->Comment(" BeginAddress");
w->Comment(" EndAddress");
w->Comment(" UnwindInfoAddress");
w->StartPdataSection();
{
Address prev_builtin_end_offset = 0;
for (int i = 0; i < Builtins::builtin_count; i++) {
// Some builtins are leaf functions from the point of view of Win64 stack
// walking: they do not move the stack pointer and do not require a PDATA
// entry because the return address can be retrieved from [rsp].
if (!blob->ContainsBuiltin(i)) continue;
if (unwind_infos[i].is_leaf_function()) continue;
uint64_t builtin_start_offset = blob->InstructionStartOfBuiltin(i) -
reinterpret_cast<Address>(blob->data());
uint32_t builtin_size = blob->InstructionSizeOfBuiltin(i);
const std::vector<int>& xdata_desc = unwind_infos[i].fp_offsets();
if (xdata_desc.empty()) {
// Some builtins do not have any "push rbp - mov rbp, rsp" instructions
// to start a stack frame. We still emit a PDATA entry as if they had,
// relying on the fact that we can find the previous frame address from
// rbp in most cases. Note that since the function does not really start
// with a 'push rbp' we need to specify the start RVA in the PDATA entry
// a few bytes before the beginning of the function, if it does not
// overlap the end of the previous builtin.
WriteUnwindInfoEntry(
w, unwind_info_symbol, embedded_blob_data_symbol,
std::max(prev_builtin_end_offset,
builtin_start_offset - win64_unwindinfo::kRbpPrefixLength),
builtin_start_offset + builtin_size);
} else {
// Some builtins have one or more "push rbp - mov rbp, rsp" sequences,
// but not necessarily at the beginning of the function. In this case
// we want to yield a PDATA entry for each block of instructions that
// emit an rbp frame. If the function does not start with 'push rbp'
// we also emit a PDATA entry for the initial block of code up to the
// first 'push rbp', like in the case above.
if (xdata_desc[0] > 0) {
WriteUnwindInfoEntry(w, unwind_info_symbol, embedded_blob_data_symbol,
std::max(prev_builtin_end_offset,
builtin_start_offset -
win64_unwindinfo::kRbpPrefixLength),
builtin_start_offset + xdata_desc[0]);
}
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;
WriteUnwindInfoEntry(w, unwind_info_symbol, embedded_blob_data_symbol,
builtin_start_offset + chunk_start,
builtin_start_offset + chunk_end);
}
}
prev_builtin_end_offset = builtin_start_offset + builtin_size;
w->Newline();
}
}
w->EndPdataSection();
w->Newline();
}
#endif // defined(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)
if (win64_unwindinfo::CanEmitUnwindInfoForBuiltins()) {
EmitUnwindData(this, unwind_info_symbol, embedded_blob_data_symbol, blob,
reinterpret_cast<const win64_unwindinfo::BuiltinUnwindInfo*>(
unwind_infos));
}
#endif // defined(V8_OS_WIN_X64)
}
// Windows, MSVC, not arm/arm64.
// -----------------------------------------------------------------------------
......
......@@ -56,6 +56,11 @@ class PlatformEmbeddedFileWriterWin : public PlatformEmbeddedFileWriterBase {
// offset from a given symbol.
void DeclareRvaToSymbol(const char* name, uint64_t offset = 0);
void MaybeEmitUnwindData(const char* unwind_info_symbol,
const char* embedded_blob_data_symbol,
const EmbeddedData* blob,
const void* unwind_infos) override;
private:
void DeclareSymbolGlobal(const char* name);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment