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