| // 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 "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 void InitUnwindingRecord(intptr_t offset, |
| CodeRangeUnwindingRecord* record, |
| size_t code_size_in_bytes) { |
| // All addresses are 32bit relative offsets to start. |
| record->runtime_function[0].BeginAddress = 0; |
| record->runtime_function[0].EndAddress = code_size_in_bytes; |
| record->runtime_function[0].UnwindData = |
| offset + offsetof(CodeRangeUnwindingRecord, unwind_info); |
| record->runtime_function_count = 1; |
| } |
| |
| 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 |
| // page on Windows for 64-bit applications. |
| 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. |
| auto function = static_cast<decltype(&::RtlAddGrowableFunctionTable)>( |
| UnwindingRecordsPlatform::GetAddGrowableFunctionTableFunc()); |
| if (function == nullptr) return; |
| ASSERT(page->is_executable()); |
| ASSERT(sizeof(CodeRangeUnwindingRecord) <= |
| UnwindingRecordsPlatform::SizeInBytes()); |
| page->top_ -= UnwindingRecordsPlatform::SizeInBytes(); |
| intptr_t unwinding_record_offset = |
| 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 (function( |
| /*DynamicTable=*/&record->dynamic_table, |
| /*FunctionTable=*/record->runtime_function, |
| /*EntryCount=*/record->runtime_function_count, |
| /*MaximumEntryCount=*/record->runtime_function_count, |
| /*RangeBase=*/page->memory_->start(), |
| /*RangeEnd=*/page->memory_->end()) != 0) { |
| FATAL("Failed to add growable function table: %d\n", GetLastError()); |
| } |
| } |
| |
| void UnwindingRecords::UnregisterExecutablePage(Page* page) { |
| 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() - UnwindingRecordsPlatform::SizeInBytes(); |
| CodeRangeUnwindingRecord* record = |
| reinterpret_cast<CodeRangeUnwindingRecord*>( |
| reinterpret_cast<uint8_t*>(page->memory_->start()) + |
| unwinding_record_offset); |
| function(record->dynamic_table); |
| } |
| |
| } // namespace dart |
| |
| #endif // defined(DART_HOST_OS_WINDOWS) |