Flutter Engine
The Flutter Engine
unwinding_records_win.cc
Go to the documentation of this file.
1// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
7#include "vm/globals.h"
8
10
11namespace dart {
12
13#if (defined(DART_TARGET_OS_WINDOWS) || defined(DART_HOST_OS_WINDOWS)) && \
14 (defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64))
15
16static void InitUnwindingRecord(intptr_t offset,
17 CodeRangeUnwindingRecord* record,
18 size_t code_size_in_bytes) {
19#if defined(TARGET_ARCH_X64)
20 // All addresses are 32bit relative offsets to start.
21 record->runtime_function[0].BeginAddress = 0;
22 record->runtime_function[0].EndAddress = code_size_in_bytes;
23 record->runtime_function[0].UnwindData =
24 offset + offsetof(CodeRangeUnwindingRecord, unwind_info);
25 record->runtime_function_count = 1;
26#elif defined(TARGET_ARCH_ARM64)
27
28 const intptr_t kInstrSize = 4;
29
30 // We assume that the first page of the code range is executable and
31 // committed and reserved to contain multiple PDATA/XDATA to cover the whole
32 // range. All addresses are 32bit relative offsets to start.
33
34 // Maximum RUNTIME_FUNCTION count available in reserved memory, this includes
35 // static part in Record as kDefaultRuntimeFunctionCount plus dynamic part in
36 // the remaining reserved memory.
37 const uint32_t max_runtime_function_count =
38 static_cast<uint32_t>((UnwindingRecordsPlatform::SizeInBytes() -
39 sizeof(CodeRangeUnwindingRecord)) /
40 sizeof(RUNTIME_FUNCTION) +
41 kDefaultRuntimeFunctionCount);
42
43 uint32_t runtime_function_index = 0;
44 uint32_t current_unwind_start_address = 0;
45 int64_t remaining_size_in_bytes = static_cast<int64_t>(code_size_in_bytes);
46
47 // Divide the code range into chunks in size kMaxFunctionLength and create a
48 // RUNTIME_FUNCTION for each of them. All the chunks in the same size can
49 // share 1 unwind_info struct, but a separate unwind_info is needed for the
50 // last chunk if it is smaller than kMaxFunctionLength, because unlike X64,
51 // unwind_info encodes the function/chunk length.
52 while (remaining_size_in_bytes >= kMaxFunctionLength &&
53 runtime_function_index < max_runtime_function_count) {
54 record->runtime_function[runtime_function_index].BeginAddress =
55 current_unwind_start_address;
56 record->runtime_function[runtime_function_index].UnwindData =
57 offset +
58 static_cast<DWORD>(offsetof(CodeRangeUnwindingRecord, unwind_info));
59
60 runtime_function_index++;
61 current_unwind_start_address += kMaxFunctionLength;
62 remaining_size_in_bytes -= kMaxFunctionLength;
63 }
64 // FunctionLength is ensured to be aligned at instruction size and Windows
65 // ARM64 doesn't encoding 2 LSB.
66 record->unwind_info.unwind_info.FunctionLength = kMaxFunctionLength >> 2;
67
68 if (remaining_size_in_bytes > 0 &&
69 runtime_function_index < max_runtime_function_count) {
70 ASSERT((remaining_size_in_bytes % kInstrSize) == 0);
71
72 record->unwind_info1.unwind_info.FunctionLength = static_cast<uint32_t>(
73 remaining_size_in_bytes >> kFunctionLengthShiftSize);
74 record->runtime_function[runtime_function_index].BeginAddress =
75 current_unwind_start_address;
76 record->runtime_function[runtime_function_index].UnwindData =
77 offset +
78 static_cast<DWORD>(offsetof(CodeRangeUnwindingRecord, unwind_info1));
79
80 remaining_size_in_bytes -= kMaxFunctionLength;
81 record->runtime_function_count = runtime_function_index + 1;
82 } else {
83 record->runtime_function_count = runtime_function_index;
84 }
85
86 // 1 page can cover kMaximalCodeRangeSize for ARM64 (128MB). If
87 // kMaximalCodeRangeSize is changed for ARM64 and makes 1 page insufficient to
88 // cover it, more pages will need to reserved for unwind data.
89 ASSERT(remaining_size_in_bytes <= 0);
90#else
91#error What architecture?
92#endif
93 record->magic = kUnwindingRecordMagic;
94}
95
97 uint8_t* target_buffer) {
98 CodeRangeUnwindingRecord* record =
99 new (target_buffer) CodeRangeUnwindingRecord();
100 InitUnwindingRecord(offset, record, offset);
101 return target_buffer;
102}
103
104#endif // (defined(DART_TARGET_OS_WINDOWS) || defined(DART_HOST_OS_WINDOWS))
105
106#if defined(DART_HOST_OS_WINDOWS) && \
107 (defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64))
108
109// Special exception-unwinding records are put at the end of executable
110// page on Windows for 64-bit applications.
112 ASSERT(page->is_executable());
113 ASSERT(sizeof(CodeRangeUnwindingRecord) <=
116 intptr_t unwinding_record_offset =
117 page->memory_->size() - UnwindingRecordsPlatform::SizeInBytes();
118 CodeRangeUnwindingRecord* record =
119 new (reinterpret_cast<uint8_t*>(page->memory_->start()) +
120 unwinding_record_offset) CodeRangeUnwindingRecord();
121 InitUnwindingRecord(unwinding_record_offset, record, page->memory_->size());
122 RELEASE_ASSERT(record->magic == kUnwindingRecordMagic);
123 DWORD status = RtlAddGrowableFunctionTable(
124 /*DynamicTable=*/&record->dynamic_table,
125 /*FunctionTable=*/record->runtime_function,
126 /*EntryCount=*/record->runtime_function_count,
127 /*MaximumEntryCount=*/record->runtime_function_count,
128 /*RangeBase=*/page->memory_->start(),
129 /*RangeEnd=*/page->memory_->end());
130 if (status != 0) {
131 FATAL("Failed to add growable function table: 0x%x\n", status);
132 }
133}
134
136 ASSERT(page->is_executable() && !page->is_image());
137 intptr_t unwinding_record_offset =
138 page->memory_->size() - UnwindingRecordsPlatform::SizeInBytes();
139 CodeRangeUnwindingRecord* record =
140 reinterpret_cast<CodeRangeUnwindingRecord*>(
141 reinterpret_cast<uint8_t*>(page->memory_->start()) +
142 unwinding_record_offset);
143 RELEASE_ASSERT(record->magic == kUnwindingRecordMagic);
144 RtlDeleteGrowableFunctionTable(record->dynamic_table);
145}
146
147#endif // defined(DART_HOST_OS_WINDOWS)
148
149} // namespace dart
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
static void UnregisterExecutablePage(Page *page)
static void RegisterExecutablePage(Page *page)
static const void * GenerateRecordsInto(intptr_t offset, uint8_t *target_buffer)
#define ASSERT(E)
#define FATAL(error)
Definition: dart_vm.cc:33
SeparatedVector2 offset
unsigned long DWORD
Definition: windows_types.h:22