[vm/win/aot] Provide unwinding information for Windows AOT snapshots.
Fixes https://github.com/dart-lang/sdk/issues/52045 TEST=ffi_induce_a_crash_test Change-Id: Ic047df10732d6ff8cf695ce098d80ec3a098dbf9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/302380 Reviewed-by: Ryan Macnak <rmacnak@google.com> Commit-Queue: Alexander Aprelev <aam@google.com>
This commit is contained in:
committed by
Commit Queue
parent
838c926f64
commit
3a668dcf03
@@ -16,6 +16,8 @@
|
||||
#include "bin/virtual_memory.h"
|
||||
#include "platform/elf.h"
|
||||
|
||||
#include "platform/unwinding_records.h"
|
||||
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
@@ -239,6 +241,12 @@ class LoadedElf {
|
||||
const dart::elf::Symbol* dynamic_symbol_table_ = nullptr;
|
||||
uword dynamic_symbol_count_ = 0;
|
||||
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(HOST_ARCH_X64)
|
||||
// Dynamic table for looking up unwinding exceptions info.
|
||||
// Initialized by LoadSegments as we load executable segment.
|
||||
MallocGrowableArray<void*> dynamic_runtime_function_tables_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LoadedElf);
|
||||
};
|
||||
|
||||
@@ -261,6 +269,7 @@ class LoadedElf {
|
||||
}
|
||||
|
||||
bool LoadedElf::Load() {
|
||||
UnwindingRecordsPlatform::Init();
|
||||
VirtualMemory::Init();
|
||||
|
||||
if (error_ != nullptr) {
|
||||
@@ -291,6 +300,13 @@ LoadedElf::~LoadedElf() {
|
||||
program_table_mapping_.reset();
|
||||
section_table_mapping_.reset();
|
||||
section_string_table_mapping_.reset();
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(HOST_ARCH_X64)
|
||||
for (intptr_t i = 0; i < dynamic_runtime_function_tables_.length(); i++) {
|
||||
UnwindingRecordsPlatform::UnregisterDynamicTable(
|
||||
dynamic_runtime_function_tables_[i]);
|
||||
}
|
||||
UnwindingRecordsPlatform::Cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LoadedElf::ReadHeader() {
|
||||
@@ -446,6 +462,16 @@ bool LoadedElf::LoadSegments() {
|
||||
CHECK_ERROR(memory != nullptr, "Could not map segment.");
|
||||
CHECK_ERROR(memory->address() == memory_start,
|
||||
"Mapping not at requested address.");
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(HOST_ARCH_X64)
|
||||
// For executable pages register unwinding information that should be
|
||||
// present on the page.
|
||||
if (map_type == File::kReadExecute) {
|
||||
void* ptable = nullptr;
|
||||
UnwindingRecordsPlatform::RegisterExecutableMemory(
|
||||
memory->address(), memory->size(), &ptable);
|
||||
dynamic_runtime_function_tables_.Add(ptable);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -32,6 +32,9 @@ platform_sources = [
|
||||
"thread_sanitizer.h",
|
||||
"unicode.cc",
|
||||
"unicode.h",
|
||||
"unwinding_records.cc",
|
||||
"unwinding_records.h",
|
||||
"unwinding_records_win.cc",
|
||||
"utils.cc",
|
||||
"utils.h",
|
||||
"utils_android.cc",
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "platform/unwinding_records.h"
|
||||
#include "vm/globals.h"
|
||||
|
||||
#if !defined(DART_HOST_OS_WINDOWS) || !defined(TARGET_ARCH_X64)
|
||||
|
||||
namespace dart {
|
||||
|
||||
void UnwindingRecordsPlatform::Init() {}
|
||||
void UnwindingRecordsPlatform::Cleanup() {}
|
||||
void UnwindingRecordsPlatform::RegisterExecutableMemory(
|
||||
void* start,
|
||||
intptr_t size,
|
||||
void** pp_dynamic_table) {}
|
||||
void UnwindingRecordsPlatform::UnregisterDynamicTable(void* p_dynamic_table) {}
|
||||
intptr_t UnwindingRecordsPlatform::SizeInBytes() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_HOST_OS_WINDOWS) || !defined(TARGET_ARCH_X64)
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
// Class for patching compiled code.
|
||||
|
||||
#ifndef RUNTIME_PLATFORM_UNWINDING_RECORDS_H_
|
||||
#define RUNTIME_PLATFORM_UNWINDING_RECORDS_H_
|
||||
|
||||
#include "platform/allocation.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class UnwindingRecordsPlatform : public AllStatic {
|
||||
public:
|
||||
static void Init();
|
||||
static void Cleanup();
|
||||
|
||||
static intptr_t SizeInBytes();
|
||||
|
||||
static void RegisterExecutableMemory(void* start,
|
||||
intptr_t size,
|
||||
void** pp_dynamic_table);
|
||||
static void UnregisterDynamicTable(void* p_dynamic_table);
|
||||
|
||||
static void* GetAddGrowableFunctionTableFunc();
|
||||
static void* GetDeleteGrowableFunctionTableFunc();
|
||||
};
|
||||
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(TARGET_ARCH_X64)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
//
|
||||
// Refer to https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64
|
||||
//
|
||||
typedef unsigned char UBYTE;
|
||||
typedef union _UNWIND_CODE {
|
||||
struct {
|
||||
UBYTE CodeOffset;
|
||||
UBYTE UnwindOp : 4;
|
||||
UBYTE OpInfo : 4;
|
||||
};
|
||||
USHORT FrameOffset;
|
||||
} UNWIND_CODE, *PUNWIND_CODE;
|
||||
|
||||
typedef struct _UNWIND_INFO {
|
||||
UBYTE Version : 3;
|
||||
UBYTE Flags : 5;
|
||||
UBYTE SizeOfProlog;
|
||||
UBYTE CountOfCodes;
|
||||
UBYTE FrameRegister : 4;
|
||||
UBYTE FrameOffset : 4;
|
||||
UNWIND_CODE UnwindCode[2];
|
||||
} UNWIND_INFO, *PUNWIND_INFO;
|
||||
|
||||
static constexpr int kPushRbpInstructionLength = 1;
|
||||
static const int kMovRbpRspInstructionLength = 3;
|
||||
static constexpr int kRbpPrefixLength =
|
||||
kPushRbpInstructionLength + kMovRbpRspInstructionLength;
|
||||
static constexpr int kRBP = 5;
|
||||
|
||||
struct GeneratedCodeUnwindInfo {
|
||||
UNWIND_INFO unwind_info;
|
||||
|
||||
GeneratedCodeUnwindInfo() {
|
||||
unwind_info.Version = 1;
|
||||
unwind_info.Flags = UNW_FLAG_NHANDLER;
|
||||
unwind_info.SizeOfProlog = kRbpPrefixLength;
|
||||
unwind_info.CountOfCodes = 2;
|
||||
unwind_info.FrameRegister = kRBP;
|
||||
unwind_info.FrameOffset = 0;
|
||||
unwind_info.UnwindCode[0].CodeOffset = kRbpPrefixLength;
|
||||
unwind_info.UnwindCode[0].UnwindOp = 3; // UWOP_SET_FPREG
|
||||
unwind_info.UnwindCode[0].OpInfo = 0;
|
||||
unwind_info.UnwindCode[1].CodeOffset = kPushRbpInstructionLength;
|
||||
unwind_info.UnwindCode[1].UnwindOp = 0; // UWOP_PUSH_NONVOL
|
||||
unwind_info.UnwindCode[1].OpInfo = kRBP;
|
||||
}
|
||||
};
|
||||
|
||||
struct CodeRangeUnwindingRecord {
|
||||
void* dynamic_table;
|
||||
uint32_t runtime_function_count;
|
||||
GeneratedCodeUnwindInfo unwind_info;
|
||||
intptr_t exception_handler;
|
||||
RUNTIME_FUNCTION runtime_function[1];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // defined(DART_HOST_OS_WINDOWS) && defined(TARGET_ARCH_X64)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_PLATFORM_UNWINDING_RECORDS_H_
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "platform/unwinding_records.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/globals.h"
|
||||
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(TARGET_ARCH_X64)
|
||||
|
||||
namespace dart {
|
||||
|
||||
static HMODULE ntdll_module;
|
||||
static decltype(
|
||||
&::RtlAddGrowableFunctionTable) add_growable_function_table_func_ = nullptr;
|
||||
static decltype(
|
||||
&::RtlDeleteGrowableFunctionTable) delete_growable_function_table_func_ =
|
||||
nullptr;
|
||||
|
||||
const intptr_t kReservedUnwindingRecordsSizeBytes = 64;
|
||||
intptr_t UnwindingRecordsPlatform::SizeInBytes() {
|
||||
return kReservedUnwindingRecordsSizeBytes;
|
||||
}
|
||||
|
||||
void* UnwindingRecordsPlatform::GetAddGrowableFunctionTableFunc() {
|
||||
return add_growable_function_table_func_;
|
||||
}
|
||||
|
||||
void* UnwindingRecordsPlatform::GetDeleteGrowableFunctionTableFunc() {
|
||||
return delete_growable_function_table_func_;
|
||||
}
|
||||
|
||||
void UnwindingRecordsPlatform::Init() {
|
||||
ntdll_module =
|
||||
LoadLibraryEx(L"ntdll.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
ASSERT(ntdll_module != nullptr);
|
||||
// This pair of functions is not available on Windows 7.
|
||||
add_growable_function_table_func_ =
|
||||
reinterpret_cast<decltype(&::RtlAddGrowableFunctionTable)>(
|
||||
::GetProcAddress(ntdll_module, "RtlAddGrowableFunctionTable"));
|
||||
delete_growable_function_table_func_ =
|
||||
reinterpret_cast<decltype(&::RtlDeleteGrowableFunctionTable)>(
|
||||
::GetProcAddress(ntdll_module, "RtlDeleteGrowableFunctionTable"));
|
||||
// Either both available, or both not available.
|
||||
ASSERT((add_growable_function_table_func_ == nullptr) ==
|
||||
(delete_growable_function_table_func_ == nullptr));
|
||||
}
|
||||
|
||||
void UnwindingRecordsPlatform::Cleanup() {
|
||||
FreeLibrary(ntdll_module);
|
||||
}
|
||||
|
||||
void UnwindingRecordsPlatform::RegisterExecutableMemory(
|
||||
void* start,
|
||||
intptr_t size,
|
||||
void** pp_dynamic_table) {
|
||||
auto func = add_growable_function_table_func_;
|
||||
if (func == nullptr) {
|
||||
return;
|
||||
}
|
||||
intptr_t unwinding_record_offset = size - kReservedUnwindingRecordsSizeBytes;
|
||||
uint8_t* record_ptr = static_cast<uint8_t*>(start) + unwinding_record_offset;
|
||||
CodeRangeUnwindingRecord* record =
|
||||
reinterpret_cast<CodeRangeUnwindingRecord*>(record_ptr);
|
||||
uword start_num = reinterpret_cast<intptr_t>(start);
|
||||
uword end_num = start_num + size;
|
||||
if (func(pp_dynamic_table,
|
||||
/*FunctionTable=*/record->runtime_function,
|
||||
/*EntryCount=*/record->runtime_function_count,
|
||||
/*MaximumEntryCount=*/record->runtime_function_count,
|
||||
/*RangeBase=*/start_num,
|
||||
/*RangeEnd=*/end_num) != 0) {
|
||||
FATAL("Failed to add growable function table: %d\n", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
void UnwindingRecordsPlatform::UnregisterDynamicTable(void* p_dynamic_table) {
|
||||
auto func = delete_growable_function_table_func_;
|
||||
if (func == nullptr) return;
|
||||
func(p_dynamic_table);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined(DART_HOST_OS_WINDOWS)
|
||||
+4
-2
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "vm/dart.h"
|
||||
|
||||
#include "platform/unwinding_records.h"
|
||||
|
||||
#include "vm/app_snapshot.h"
|
||||
#include "vm/code_observers.h"
|
||||
#include "vm/compiler/runtime_offsets_extracted.h"
|
||||
@@ -334,7 +336,7 @@ char* Dart::DartInit(const Dart_InitializeParams* params) {
|
||||
Api::Init();
|
||||
NativeSymbolResolver::Init();
|
||||
NOT_IN_PRODUCT(Profiler::Init());
|
||||
UnwindingRecords::Init();
|
||||
UnwindingRecordsPlatform::Init();
|
||||
Page::Init();
|
||||
StoreBuffer::Init();
|
||||
MarkingStack::Init();
|
||||
@@ -767,7 +769,7 @@ char* Dart::Cleanup() {
|
||||
StoreBuffer::Cleanup();
|
||||
Object::Cleanup();
|
||||
Page::Cleanup();
|
||||
UnwindingRecords::Cleanup();
|
||||
UnwindingRecordsPlatform::Cleanup();
|
||||
StubCode::Cleanup();
|
||||
#if defined(SUPPORT_TIMELINE)
|
||||
if (FLAG_trace_shutdown) {
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
#include "vm/elf.h"
|
||||
|
||||
#include "platform/elf.h"
|
||||
#include "platform/unwinding_records.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/dwarf.h"
|
||||
#include "vm/hash_map.h"
|
||||
#include "vm/image_snapshot.h"
|
||||
#include "vm/stack_frame.h"
|
||||
#include "vm/thread.h"
|
||||
#include "vm/unwinding_records.h"
|
||||
#include "vm/zone_text_buffer.h"
|
||||
|
||||
namespace dart {
|
||||
@@ -1409,6 +1411,28 @@ void Elf::FinalizeEhFrame() {
|
||||
// No text section added means no .eh_frame.
|
||||
if (text_section == nullptr) return;
|
||||
|
||||
#if defined(DART_TARGET_OS_WINDOWS) && defined(TARGET_ARCH_X64)
|
||||
// Append Windows unwinding instructions to the end of .text section.
|
||||
{
|
||||
auto* const unwinding_instructions_frame = new (zone_) TextSection(type_);
|
||||
ZoneWriteStream stream(
|
||||
zone(),
|
||||
/*initial_size=*/UnwindingRecordsPlatform::SizeInBytes());
|
||||
uint8_t* unwinding_instructions =
|
||||
zone()->Alloc<uint8_t>(UnwindingRecordsPlatform::SizeInBytes());
|
||||
|
||||
intptr_t start_offset =
|
||||
Utils::RoundUp(text_section->FileSize(), text_section->alignment);
|
||||
stream.WriteBytes(UnwindingRecords::GenerateRecordsInto(
|
||||
start_offset, unwinding_instructions),
|
||||
UnwindingRecordsPlatform::SizeInBytes());
|
||||
|
||||
unwinding_instructions_frame->AddPortion(stream.buffer(),
|
||||
stream.bytes_written());
|
||||
section_table_->Add(unwinding_instructions_frame, kTextName);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Multiplier which will be used to scale operands of DW_CFA_offset and
|
||||
// DW_CFA_val_offset.
|
||||
const intptr_t kDataAlignment = -compiler::target::kWordSize;
|
||||
@@ -1449,6 +1473,12 @@ void Elf::FinalizeEhFrame() {
|
||||
|
||||
// Emit an FDE covering each .text section.
|
||||
for (const auto& portion : text_section->portions()) {
|
||||
#if defined(DART_TARGET_OS_WINDOWS) && defined(TARGET_ARCH_X64)
|
||||
if (portion.label == 0) {
|
||||
// Unwinding instructions sections doesn't have label, doesn't dwarf
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
ASSERT(portion.label != 0); // Needed for relocations.
|
||||
dwarf_stream.WritePrefixedLength([&]() {
|
||||
// Offset to CIE. Note that unlike pcrel this offset is encoded
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "platform/leak_sanitizer.h"
|
||||
#include "platform/unwinding_records.h"
|
||||
#include "vm/dart.h"
|
||||
#include "vm/heap/become.h"
|
||||
#include "vm/heap/compactor.h"
|
||||
@@ -217,7 +218,7 @@ Page* PageSpace::AllocatePage(bool is_exec, bool link) {
|
||||
|
||||
Page* PageSpace::AllocateLargePage(intptr_t size, bool is_exec) {
|
||||
const intptr_t page_size_in_words = LargePageSizeInWordsFor(
|
||||
size + (is_exec ? UnwindingRecords::SizeInBytes() : 0));
|
||||
size + (is_exec ? UnwindingRecordsPlatform::SizeInBytes() : 0));
|
||||
{
|
||||
MutexLocker ml(&pages_lock_);
|
||||
if (!CanIncreaseCapacityInWordsLocked(page_size_in_words)) {
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
void UnwindingRecords::Init() {}
|
||||
void UnwindingRecords::Cleanup() {}
|
||||
intptr_t UnwindingRecords::SizeInBytes() {
|
||||
return 0;
|
||||
}
|
||||
void UnwindingRecords::RegisterExecutablePage(Page* page) {}
|
||||
void UnwindingRecords::UnregisterExecutablePage(Page* page) {}
|
||||
|
||||
|
||||
@@ -13,9 +13,8 @@ namespace dart {
|
||||
|
||||
class UnwindingRecords : public AllStatic {
|
||||
public:
|
||||
static void Init();
|
||||
static void Cleanup();
|
||||
static intptr_t SizeInBytes();
|
||||
static const void* GenerateRecordsInto(intptr_t offset,
|
||||
uint8_t* target_buffer);
|
||||
static void RegisterExecutablePage(Page* page);
|
||||
static void UnregisterExecutablePage(Page* page);
|
||||
};
|
||||
|
||||
@@ -2,99 +2,16 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#include "vm/unwinding_records.h"
|
||||
|
||||
#include "vm/globals.h"
|
||||
|
||||
#include "platform/unwinding_records.h"
|
||||
|
||||
#if defined(DART_HOST_OS_WINDOWS) && defined(TARGET_ARCH_X64)
|
||||
|
||||
namespace dart {
|
||||
|
||||
static HMODULE ntdll_module;
|
||||
static decltype(
|
||||
&::RtlAddGrowableFunctionTable) add_growable_function_table_func = nullptr;
|
||||
static decltype(
|
||||
&::RtlDeleteGrowableFunctionTable) delete_growable_function_table_func =
|
||||
nullptr;
|
||||
|
||||
void UnwindingRecords::Init() {
|
||||
ntdll_module =
|
||||
LoadLibraryEx(L"ntdll.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
ASSERT(ntdll_module != nullptr);
|
||||
// This pair of functions is not available on Windows 7.
|
||||
add_growable_function_table_func =
|
||||
reinterpret_cast<decltype(&::RtlAddGrowableFunctionTable)>(
|
||||
::GetProcAddress(ntdll_module, "RtlAddGrowableFunctionTable"));
|
||||
delete_growable_function_table_func =
|
||||
reinterpret_cast<decltype(&::RtlDeleteGrowableFunctionTable)>(
|
||||
::GetProcAddress(ntdll_module, "RtlDeleteGrowableFunctionTable"));
|
||||
// Either both available, or both not available.
|
||||
ASSERT((add_growable_function_table_func == nullptr) ==
|
||||
(delete_growable_function_table_func == nullptr));
|
||||
}
|
||||
|
||||
void UnwindingRecords::Cleanup() {
|
||||
FreeLibrary(ntdll_module);
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
//
|
||||
// Refer to https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64
|
||||
//
|
||||
typedef unsigned char UBYTE;
|
||||
typedef union _UNWIND_CODE {
|
||||
struct {
|
||||
UBYTE CodeOffset;
|
||||
UBYTE UnwindOp : 4;
|
||||
UBYTE OpInfo : 4;
|
||||
};
|
||||
USHORT FrameOffset;
|
||||
} UNWIND_CODE, *PUNWIND_CODE;
|
||||
|
||||
typedef struct _UNWIND_INFO {
|
||||
UBYTE Version : 3;
|
||||
UBYTE Flags : 5;
|
||||
UBYTE SizeOfProlog;
|
||||
UBYTE CountOfCodes;
|
||||
UBYTE FrameRegister : 4;
|
||||
UBYTE FrameOffset : 4;
|
||||
UNWIND_CODE UnwindCode[2];
|
||||
} UNWIND_INFO, *PUNWIND_INFO;
|
||||
|
||||
static constexpr int kPushRbpInstructionLength = 1;
|
||||
static const int kMovRbpRspInstructionLength = 3;
|
||||
static constexpr int kRbpPrefixLength =
|
||||
kPushRbpInstructionLength + kMovRbpRspInstructionLength;
|
||||
static constexpr int kRBP = 5;
|
||||
|
||||
struct GeneratedCodeUnwindInfo {
|
||||
UNWIND_INFO unwind_info;
|
||||
|
||||
GeneratedCodeUnwindInfo() {
|
||||
unwind_info.Version = 1;
|
||||
unwind_info.Flags = UNW_FLAG_NHANDLER;
|
||||
unwind_info.SizeOfProlog = kRbpPrefixLength;
|
||||
unwind_info.CountOfCodes = 2;
|
||||
unwind_info.FrameRegister = kRBP;
|
||||
unwind_info.FrameOffset = 0;
|
||||
unwind_info.UnwindCode[0].CodeOffset = kRbpPrefixLength;
|
||||
unwind_info.UnwindCode[0].UnwindOp = 3; // UWOP_SET_FPREG
|
||||
unwind_info.UnwindCode[0].OpInfo = 0;
|
||||
unwind_info.UnwindCode[1].CodeOffset = kPushRbpInstructionLength;
|
||||
unwind_info.UnwindCode[1].UnwindOp = 0; // UWOP_PUSH_NONVOL
|
||||
unwind_info.UnwindCode[1].OpInfo = kRBP;
|
||||
}
|
||||
};
|
||||
|
||||
struct CodeRangeUnwindingRecord {
|
||||
void* dynamic_table;
|
||||
uint32_t runtime_function_count;
|
||||
GeneratedCodeUnwindInfo unwind_info;
|
||||
intptr_t exception_handler;
|
||||
RUNTIME_FUNCTION runtime_function[1];
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static void InitUnwindingRecord(intptr_t offset,
|
||||
CodeRangeUnwindingRecord* record,
|
||||
size_t code_size_in_bytes) {
|
||||
@@ -106,11 +23,12 @@ static void InitUnwindingRecord(intptr_t offset,
|
||||
record->runtime_function_count = 1;
|
||||
}
|
||||
|
||||
const intptr_t kReservedUnwindingRecordsSizeBytes = 64;
|
||||
COMPILE_ASSERT(kReservedUnwindingRecordsSizeBytes >
|
||||
sizeof(CodeRangeUnwindingRecord));
|
||||
intptr_t UnwindingRecords::SizeInBytes() {
|
||||
return kReservedUnwindingRecordsSizeBytes;
|
||||
const void* UnwindingRecords::GenerateRecordsInto(intptr_t offset,
|
||||
uint8_t* target_buffer) {
|
||||
CodeRangeUnwindingRecord* record =
|
||||
new (target_buffer) CodeRangeUnwindingRecord();
|
||||
InitUnwindingRecord(offset, record, offset);
|
||||
return target_buffer;
|
||||
}
|
||||
|
||||
// Special exception-unwinding records are put at the end of executable
|
||||
@@ -118,16 +36,20 @@ intptr_t UnwindingRecords::SizeInBytes() {
|
||||
void UnwindingRecords::RegisterExecutablePage(Page* page) {
|
||||
// Won't set up unwinding records on Windows 7, so users won't be able
|
||||
// to benefit from proper unhandled exceptions filtering.
|
||||
if (add_growable_function_table_func == nullptr) return;
|
||||
auto function = static_cast<decltype(&::RtlAddGrowableFunctionTable)>(
|
||||
UnwindingRecordsPlatform::GetAddGrowableFunctionTableFunc());
|
||||
if (function == nullptr) return;
|
||||
ASSERT(page->is_executable());
|
||||
page->top_ -= kReservedUnwindingRecordsSizeBytes;
|
||||
ASSERT(sizeof(CodeRangeUnwindingRecord) <=
|
||||
UnwindingRecordsPlatform::SizeInBytes());
|
||||
page->top_ -= UnwindingRecordsPlatform::SizeInBytes();
|
||||
intptr_t unwinding_record_offset =
|
||||
page->memory_->size() - kReservedUnwindingRecordsSizeBytes;
|
||||
page->memory_->size() - UnwindingRecordsPlatform::SizeInBytes();
|
||||
CodeRangeUnwindingRecord* record =
|
||||
new (reinterpret_cast<uint8_t*>(page->memory_->start()) +
|
||||
unwinding_record_offset) CodeRangeUnwindingRecord();
|
||||
InitUnwindingRecord(unwinding_record_offset, record, page->memory_->size());
|
||||
if (add_growable_function_table_func(
|
||||
if (function(
|
||||
/*DynamicTable=*/&record->dynamic_table,
|
||||
/*FunctionTable=*/record->runtime_function,
|
||||
/*EntryCount=*/record->runtime_function_count,
|
||||
@@ -139,15 +61,17 @@ void UnwindingRecords::RegisterExecutablePage(Page* page) {
|
||||
}
|
||||
|
||||
void UnwindingRecords::UnregisterExecutablePage(Page* page) {
|
||||
if (delete_growable_function_table_func == nullptr) return;
|
||||
auto function = static_cast<decltype(&::RtlDeleteGrowableFunctionTable)>(
|
||||
UnwindingRecordsPlatform::GetDeleteGrowableFunctionTableFunc());
|
||||
if (function == nullptr) return;
|
||||
ASSERT(page->is_executable() && !page->is_image());
|
||||
intptr_t unwinding_record_offset =
|
||||
page->memory_->size() - kReservedUnwindingRecordsSizeBytes;
|
||||
page->memory_->size() - UnwindingRecordsPlatform::SizeInBytes();
|
||||
CodeRangeUnwindingRecord* record =
|
||||
reinterpret_cast<CodeRangeUnwindingRecord*>(
|
||||
reinterpret_cast<uint8_t*>(page->memory_->start()) +
|
||||
unwinding_record_offset);
|
||||
delete_growable_function_table_func(record->dynamic_table);
|
||||
function(record->dynamic_table);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
@@ -19,8 +19,6 @@ import 'dylib_utils.dart';
|
||||
void main(List<String> args) async {
|
||||
// Test exercises JIT, Windows-only functionality.
|
||||
if (!Platform.isWindows) return;
|
||||
if (path.basenameWithoutExtension(Platform.executable) ==
|
||||
'dart_precompiled_runtime') return;
|
||||
if (args.length == 0) {
|
||||
asyncStart();
|
||||
final results = await Process.run(
|
||||
|
||||
Reference in New Issue
Block a user