OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_EH_FRAME_H_ | 5 #ifndef V8_EH_FRAME_H_ |
6 #define V8_EH_FRAME_H_ | 6 #define V8_EH_FRAME_H_ |
7 | 7 |
8 #include <cstdint> | 8 #include "src/macro-assembler.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
11 namespace internal { | 11 namespace internal { |
12 | 12 |
13 class Code; | 13 struct EhFrameConstants final { |
rmcilroy
2016/07/07 10:11:03
class
Stefano Sanfilippo
2016/07/07 10:57:00
Done.
| |
14 | 14 enum class DwarfOpcodes : byte { |
15 class EhFrameHdr final { | 15 kNop = 0x00, |
16 kAdvanceLoc1 = 0x02, | |
17 kAdvanceLoc2 = 0x03, | |
18 kAdvanceLoc4 = 0x04, | |
19 kSameValue = 0x08, | |
20 kDefCfa = 0x0c, | |
21 kDefCfaRegister = 0x0d, | |
22 kDefCfaOffset = 0x0e, | |
23 kOffsetExtendedSf = 0x11, | |
24 }; | |
25 | |
26 enum DwarfEncodingSpecifiers : byte { | |
27 kUData4 = 0x03, | |
28 kSData4 = 0x0b, | |
29 kPcRel = 0x10, | |
30 kDataRel = 0x30, | |
31 kOmit = 0xff, | |
32 }; | |
33 | |
34 static const int kLocationTag = 1; | |
35 static const int kLocationMask = 0x3f; | |
36 static const int kLocationMaskSize = 6; | |
37 | |
38 static const int kSavedRegisterTag = 2; | |
39 static const int kSavedRegisterMask = 0x3f; | |
40 static const int kSavedRegisterMaskSize = 6; | |
41 | |
42 static const int kFollowInitialRuleTag = 3; | |
43 static const int kFollowInitialRuleMask = 0x3f; | |
44 static const int kFollowInitialRuleMaskSize = 6; | |
45 | |
46 static const int kProcedureAddressOffsetInFde = 2 * kInt32Size; | |
47 static const int kProcedureSizeOffsetInFde = 3 * kInt32Size; | |
48 | |
49 static const int kInitialStateOffsetInCIE = 19; | |
50 static const int kEhFrameTerminatorSize = 4; | |
51 | |
52 static const int kDataAlignmentFactor; | |
rmcilroy
2016/07/07 10:11:03
Add a comment that this is defined in eh-writer-<a
Stefano Sanfilippo
2016/07/07 10:57:00
Done.
| |
53 | |
54 static const int kFdeVersionSize = 1; | |
55 static const int kFdeEncodingSpecifiersSize = 3; | |
56 | |
57 static const int kEhFrameHdrVersion = 1; | |
58 static const int kEhFrameHdrSize = 20; | |
59 | |
60 static const byte kDummyEhFrame[kEhFrameHdrSize]; | |
rmcilroy
2016/07/07 10:11:03
Don't make this a static with static initializatio
Stefano Sanfilippo
2016/07/07 10:57:00
Done.
| |
61 }; | |
62 | |
63 class EhFrameWriter { | |
16 public: | 64 public: |
17 static const int kRecordSize = 20; | 65 explicit EhFrameWriter(Zone* zone); |
18 static const int kCIESize; | 66 |
19 | 67 void AdvanceLocation(int pc_offset); |
20 explicit EhFrameHdr(Code* code); | 68 |
21 | 69 // The <base_address> is the one to which all <offset>s in SaveRegisterToStack |
22 int32_t offset_to_eh_frame() const { return offset_to_eh_frame_; } | 70 // directives are relative. It is given by <base_register> + <base_offset>. |
23 uint32_t lut_entries_number() const { return lut_entries_number_; } | 71 void SetBaseAddressRegister(Register base_register); |
24 int32_t offset_to_procedure() const { return offset_to_procedure_; } | 72 void SetBaseAddressOffset(int base_offset); |
25 int32_t offset_to_fde() const { return offset_to_fde_; } | 73 void IncreaseBaseAddressOffset(int base_delta) { |
74 SetBaseAddressOffset(base_offset_ + base_delta); | |
75 } | |
76 void SetBaseAddressRegisterAndOffset(Register base_register, int base_offset); | |
77 | |
78 // Register saved at location <base_address> + <offset> | |
79 void RecordRegisterSavedToStack(Register name, int offset) { | |
80 RecordRegisterSavedToStack(RegisterToDwarfCode(name), offset); | |
81 } | |
82 | |
83 // The content of the register is valid (by default, it is undefined). | |
84 void RecordRegisterIsValid(Register name); | |
85 | |
86 // The register follows the rule defined in the CIE. | |
87 void RecordRegisterFollowsInitialRule(Register name); | |
88 | |
89 void Finish(int code_size); | |
90 | |
91 // Remember to call Finish() before GetEhFrame(). | |
92 // | |
93 // The EhFrameWriter instance owns the buffer pointed by | |
94 // CodeDesc::unwinding_info, and must outlive any use of the CodeDesc. | |
95 void GetEhFrame(CodeDesc* desc); | |
96 | |
97 int last_pc_offset() const { return last_pc_offset_; } | |
98 Register base_register() const { return base_register_; } | |
99 int base_offset() const { return base_offset_; } | |
26 | 100 |
27 private: | 101 private: |
28 uint8_t version_; | 102 static const uint32_t kInt32Placeholder = 0xdeadc0de; |
29 uint8_t eh_frame_ptr_encoding_; | 103 |
30 uint8_t lut_size_encoding_; | 104 static int RegisterToDwarfCode(Register name); |
31 uint8_t lut_entries_encoding_; | 105 |
32 int32_t offset_to_eh_frame_; | 106 void WriteSLEB128(int32_t value); |
33 uint32_t lut_entries_number_; | 107 void WriteULEB128(uint32_t value); |
34 int32_t offset_to_procedure_; | 108 |
35 int32_t offset_to_fde_; | 109 void WriteByte(byte value) { eh_frame_buffer_.push_back(value); } |
36 }; | 110 void WriteOpcode(EhFrameConstants::DwarfOpcodes opcode) { |
111 WriteByte(static_cast<byte>(opcode)); | |
112 } | |
113 void WriteBytes(const byte* start, int size) { | |
114 eh_frame_buffer_.insert(eh_frame_buffer_.end(), start, start + size); | |
115 } | |
116 void WriteInt16(uint16_t value) { | |
117 WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value)); | |
118 } | |
119 void WriteInt32(uint32_t value) { | |
120 WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value)); | |
121 } | |
122 void PatchInt32(int base_offset, uint32_t value) { | |
123 DCHECK_EQ(ReadUnalignedUInt32(eh_frame_buffer_.data() + base_offset), | |
124 kInt32Placeholder); | |
125 DCHECK_LT(base_offset + kInt32Size, eh_frame_offset()); | |
126 WriteUnalignedUInt32(eh_frame_buffer_.data() + base_offset, value); | |
127 } | |
128 | |
129 // Write the common information entry, which includes encoding specifiers, | |
130 // alignment factors, the return address (pseudo) register code and the | |
131 // directives to construct the initial state of the unwinding table. | |
132 void WriteCIE(); | |
133 | |
134 // Write directives to build the initial state in the CIE. | |
135 // This bit is platform specific. | |
rmcilroy
2016/07/07 10:11:03
Don't use "bit". If you want group all the archite
Stefano Sanfilippo
2016/07/07 10:57:00
Done.
| |
136 void WriteInitialStateInCIE(); | |
137 | |
138 // Write the return address (pseudo) register code. | |
139 void WriteReturnAddressRegisterCode(); | |
140 | |
141 // Write the header of the function data entry, containing a pointer to the | |
142 // correspondent CIE and the position and size of the associated routine. | |
143 void WriteFDEHeader(); | |
144 | |
145 // Write the contents of the .eh_frame_hdr section, including encoder | |
146 // specifiers and the routine => FDE lookup table. | |
147 void WriteEhFrameHdr(int code_size); | |
148 | |
149 // Write nops to the buffer until the size reaches a multiple of 8 bytes. | |
150 void WritePaddingTo8ByteAlignment(); | |
151 | |
152 // Internal version that directly accepts a DWARF register code, needed for | |
153 // handling pseudoregisters on some platforms, such as x64. | |
rmcilroy
2016/07/07 10:11:03
pseudo-registers and drop the ", such as x64"
Stefano Sanfilippo
2016/07/07 10:57:00
Done.
| |
154 void RecordRegisterSavedToStack(int register_code, int offset); | |
155 | |
156 int GetProcedureAddressOffset() const { | |
157 return fde_offset() + EhFrameConstants::kProcedureAddressOffsetInFde; | |
158 } | |
159 | |
160 int GetProcedureSizeOffset() const { | |
161 return fde_offset() + EhFrameConstants::kProcedureSizeOffsetInFde; | |
162 } | |
163 | |
164 int eh_frame_offset() const { | |
165 return static_cast<int>(eh_frame_buffer_.size()); | |
166 } | |
167 | |
168 int fde_offset() const { return cie_size_; } | |
169 | |
170 int cie_size_; | |
171 int last_pc_offset_; | |
172 bool eh_frame_finalised_; | |
173 Register base_register_; | |
174 int base_offset_; | |
175 ZoneVector<byte> eh_frame_buffer_; | |
176 }; | |
177 | |
178 class EhFrameIterator { | |
179 public: | |
180 EhFrameIterator(const byte* start, const byte* end) | |
181 : start_(start), next_(start), end_(end) { | |
182 DCHECK_LE(start, end); | |
183 } | |
184 | |
185 void SkipCIE() { | |
186 DCHECK_EQ(next_, start_); | |
187 next_ += ReadUnalignedUInt32(next_) + kInt32Size; | |
188 } | |
189 | |
190 void SkipToFDEDirectives() { | |
191 SkipCIE(); | |
192 // Skip the FDE header. | |
193 Skip(kDirectivesOffsetInFDE); | |
194 } | |
195 | |
196 void Skip(int how_many) { | |
197 DCHECK_GE(how_many, 0); | |
198 next_ += how_many; | |
199 DCHECK_LE(next_, end_); | |
200 } | |
201 | |
202 uint32_t GetNextUInt32() { return GetNextValue<uint32_t>(); } | |
203 uint16_t GetNextUInt16() { return GetNextValue<uint16_t>(); } | |
204 byte GetNextByte() { return GetNextValue<byte>(); } | |
205 EhFrameConstants::DwarfOpcodes GetNextOpcode() { | |
206 return static_cast<EhFrameConstants::DwarfOpcodes>(GetNextByte()); | |
207 } | |
208 | |
209 uint32_t GetNextULEB128(); | |
210 int32_t GetNextSLEB128(); | |
211 | |
212 bool Done() const { | |
213 DCHECK_LE(next_, end_); | |
214 return next_ == end_; | |
215 } | |
216 | |
217 int GetCurrentOffset() const { | |
218 DCHECK_GE(next_, start_); | |
219 return static_cast<int>(next_ - start_); | |
220 } | |
221 | |
222 int GetBufferSize() { return static_cast<int>(end_ - start_); } | |
223 | |
224 const void* current_address() const { | |
225 return reinterpret_cast<const void*>(next_); | |
226 } | |
227 | |
228 private: | |
229 static const int kDirectivesOffsetInFDE = 4 * kInt32Size + 1; | |
230 | |
231 static uint32_t DecodeULEB128(const byte* encoded, int* encoded_size); | |
232 static int32_t DecodeSLEB128(const byte* encoded, int* encoded_size); | |
233 | |
234 template <typename T> | |
235 T GetNextValue() { | |
236 T result; | |
237 DCHECK_LE(next_ + sizeof(result), end_); | |
238 result = ReadUnalignedValue<T>(next_); | |
239 next_ += sizeof(result); | |
240 return result; | |
241 } | |
242 | |
243 const byte* start_; | |
244 const byte* next_; | |
245 const byte* end_; | |
246 }; | |
247 | |
248 #ifdef ENABLE_DISASSEMBLER | |
249 | |
250 class EhFrameDisassembler final { | |
251 public: | |
252 EhFrameDisassembler(const byte* start, const byte* end) | |
253 : start_(start), end_(end) { | |
254 DCHECK_LT(start, end); | |
255 } | |
256 | |
257 void DisassembleToStream(std::ostream& stream); // NOLINT | |
258 | |
259 private: | |
260 static void DumpDWARFDirectives(std::ostream& stream, // NOLINT | |
261 const byte* start, const byte* end); | |
262 | |
263 static const char* DwarfRegisterCodeToString(int code); | |
264 | |
265 const byte* start_; | |
266 const byte* end_; | |
267 }; | |
268 | |
269 #endif | |
37 | 270 |
38 } // namespace internal | 271 } // namespace internal |
39 } // namespace v8 | 272 } // namespace v8 |
40 | 273 |
41 #endif | 274 #endif |
OLD | NEW |