v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
eh-frame.h
Go to the documentation of this file.
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
3// found in the LICENSE file.
4
5#ifndef V8_DIAGNOSTICS_EH_FRAME_H_
6#define V8_DIAGNOSTICS_EH_FRAME_H_
7
9#include "src/base/memory.h"
11#include "src/common/globals.h"
13
14namespace v8 {
15namespace internal {
16
17class CodeDesc;
18
20 : public NON_EXPORTED_BASE(AllStatic) {
21 public:
22 enum class DwarfOpcodes : uint8_t {
23 kNop = 0x00,
24 kAdvanceLoc1 = 0x02,
25 kAdvanceLoc2 = 0x03,
26 kAdvanceLoc4 = 0x04,
27 kRestoreExtended = 0x06,
28 kSameValue = 0x08,
29 kDefCfa = 0x0c,
30 kDefCfaRegister = 0x0d,
31 kDefCfaOffset = 0x0e,
32 kOffsetExtendedSf = 0x11,
33 };
34
35 enum DwarfEncodingSpecifiers : uint8_t {
36 kUData4 = 0x03,
37 kSData4 = 0x0b,
38 kPcRel = 0x10,
39 kDataRel = 0x30,
40 kOmit = 0xff,
41 };
42
43 static const int kLocationTag = 1;
44 static const int kLocationMask = 0x3f;
45 static const int kLocationMaskSize = 6;
46
47 static const int kSavedRegisterTag = 2;
48 static const int kSavedRegisterMask = 0x3f;
49 static const int kSavedRegisterMaskSize = 6;
50
51 static const int kFollowInitialRuleTag = 3;
52 static const int kFollowInitialRuleMask = 0x3f;
53 static const int kFollowInitialRuleMaskSize = 6;
54
55 static const int kProcedureAddressOffsetInFde = 2 * kInt32Size;
56 static const int kProcedureSizeOffsetInFde = 3 * kInt32Size;
57
58 static const int kInitialStateOffsetInCie = 19;
59 static const int kEhFrameTerminatorSize = 4;
60
61 // Defined in eh-writer-<arch>.cc
62 static const int kCodeAlignmentFactor;
63 static const int kDataAlignmentFactor;
64
65 static const int kFdeVersionSize = 1;
66 static const int kFdeEncodingSpecifiersSize = 3;
67
68 static const int kEhFrameHdrVersion = 1;
69 static const int kEhFrameHdrSize = 20;
70};
71
73 public:
74 explicit EhFrameWriter(Zone* zone);
75 EhFrameWriter(const EhFrameWriter&) = delete;
77
78 // The empty frame is a hack to trigger fp-based unwinding in Linux perf
79 // compiled with libunwind support when processing DWARF-based call graphs.
80 //
81 // It is effectively a valid eh_frame_hdr with an empty look up table.
82 //
83 static void WriteEmptyEhFrame(std::ostream& stream);
84
85 // Write the CIE and FDE header. Call it before any other method.
86 void Initialize();
87
88 void AdvanceLocation(int pc_offset);
89
90 // The <base_address> is the one to which all <offset>s in SaveRegisterToStack
91 // directives are relative. It is given by <base_register> + <base_offset>.
92 //
93 // The <base_offset> must be positive or 0.
94 //
95 void SetBaseAddressRegister(Register base_register);
96 void SetBaseAddressOffset(int base_offset);
97 void IncreaseBaseAddressOffset(int base_delta) {
98 SetBaseAddressOffset(base_offset_ + base_delta);
99 }
100 void SetBaseAddressRegisterAndOffset(Register base_register, int base_offset);
101
102 // Register saved at location <base_address> + <offset>.
103 // The <offset> must be a multiple of EhFrameConstants::kDataAlignment.
105 RecordRegisterSavedToStack(RegisterToDwarfCode(name), offset);
106 }
107
108 // Directly accepts a DWARF register code, needed for
109 // handling pseudo-registers on some platforms.
110 void RecordRegisterSavedToStack(int dwarf_register_code, int offset);
111
112 // The register has not been modified from the previous frame.
113 void RecordRegisterNotModified(Register name);
114 void RecordRegisterNotModified(int dwarf_register_code);
115
116 // The register follows the rule defined in the CIE.
117 void RecordRegisterFollowsInitialRule(Register name);
118 void RecordRegisterFollowsInitialRule(int dwarf_register_code);
119
120 void Finish(int code_size);
121
122 // Remember to call Finish() before GetEhFrame().
123 //
124 // The EhFrameWriter instance owns the buffer pointed by
125 // CodeDesc::unwinding_info, and must outlive any use of the CodeDesc.
126 //
127 void GetEhFrame(CodeDesc* desc);
128
129 int last_pc_offset() const { return last_pc_offset_; }
130 Register base_register() const { return base_register_; }
131 int base_offset() const { return base_offset_; }
132
133 private:
134 enum class InternalState { kUndefined, kInitialized, kFinalized };
135
136 static const uint32_t kInt32Placeholder = 0xdeadc0de;
137
138 void WriteSLeb128(int32_t value);
139 void WriteULeb128(uint32_t value);
140
141 void WriteByte(uint8_t value) { eh_frame_buffer_.push_back(value); }
143 WriteByte(static_cast<uint8_t>(opcode));
144 }
145 void WriteBytes(const uint8_t* start, int size) {
146 eh_frame_buffer_.insert(eh_frame_buffer_.end(), start, start + size);
147 }
148 void WriteInt16(uint16_t value) {
149 WriteBytes(reinterpret_cast<const uint8_t*>(&value), sizeof(value));
150 }
151 void WriteInt32(uint32_t value) {
152 WriteBytes(reinterpret_cast<const uint8_t*>(&value), sizeof(value));
153 }
154 void PatchInt32(int base_offset, uint32_t value) {
155 DCHECK_EQ(
156 base::ReadUnalignedValue<uint32_t>(
157 reinterpret_cast<Address>(eh_frame_buffer_.data()) + base_offset),
158 kInt32Placeholder);
159 DCHECK_LT(base_offset + kInt32Size, eh_frame_offset());
160 base::WriteUnalignedValue<uint32_t>(
161 reinterpret_cast<Address>(eh_frame_buffer_.data()) + base_offset,
162 value);
163 }
164
165 // Write the common information entry, which includes encoding specifiers,
166 // alignment factors, the return address (pseudo) register code and the
167 // directives to construct the initial state of the unwinding table.
168 void WriteCie();
169
170 // Write the header of the function data entry, containing a pointer to the
171 // correspondent CIE and the position and size of the associated routine.
172 void WriteFdeHeader();
173
174 // Write the contents of the .eh_frame_hdr section, including encoding
175 // specifiers and the routine => FDE lookup table.
176 void WriteEhFrameHdr(int code_size);
177
178 // Write nops until the size reaches a multiple of 8 bytes.
179 void WritePaddingToAlignedSize(int unpadded_size);
180
182 return fde_offset() + EhFrameConstants::kProcedureAddressOffsetInFde;
183 }
184
186 return fde_offset() + EhFrameConstants::kProcedureSizeOffsetInFde;
187 }
188
189 int eh_frame_offset() const {
190 return static_cast<int>(eh_frame_buffer_.size());
191 }
192
193 int fde_offset() const { return cie_size_; }
194
195 // Platform specific functions implemented in eh-frame-<arch>.cc
196
197 static int RegisterToDwarfCode(Register name);
198
199 // Write directives to build the initial state in the CIE.
200 void WriteInitialStateInCie();
201
202 // Write the return address (pseudo) register code.
203 void WriteReturnAddressRegisterCode();
204
211};
212
214 public:
215 EhFrameIterator(const uint8_t* start, const uint8_t* end)
216 : start_(start), next_(start), end_(end) {
218 }
219
220 void SkipCie() {
221 DCHECK_EQ(next_, start_);
222 next_ +=
223 base::ReadUnalignedValue<uint32_t>(reinterpret_cast<Address>(next_)) +
225 }
226
228 SkipCie();
229 // Skip the FDE header.
230 Skip(kDirectivesOffsetInFde);
231 }
232
233 void Skip(int how_many) {
234 DCHECK_GE(how_many, 0);
235 next_ += how_many;
236 DCHECK_LE(next_, end_);
237 }
238
239 uint32_t GetNextUInt32() { return GetNextValue<uint32_t>(); }
240 uint16_t GetNextUInt16() { return GetNextValue<uint16_t>(); }
241 uint8_t GetNextByte() { return GetNextValue<uint8_t>(); }
243 return static_cast<EhFrameConstants::DwarfOpcodes>(GetNextByte());
244 }
245
246 uint32_t GetNextULeb128();
247 int32_t GetNextSLeb128();
248
249 bool Done() const {
250 DCHECK_LE(next_, end_);
251 return next_ == end_;
252 }
253
254 int GetCurrentOffset() const {
255 DCHECK_GE(next_, start_);
256 return static_cast<int>(next_ - start_);
257 }
258
259 int GetBufferSize() { return static_cast<int>(end_ - start_); }
260
261 const void* current_address() const {
262 return reinterpret_cast<const void*>(next_);
263 }
264
265 private:
266 static const int kDirectivesOffsetInFde = 4 * kInt32Size + 1;
267
268 static uint32_t DecodeULeb128(const uint8_t* encoded, int* encoded_size);
269 static int32_t DecodeSLeb128(const uint8_t* encoded, int* encoded_size);
270
271 template <typename T>
273 T result;
274 DCHECK_LE(next_ + sizeof(result), end_);
275 result = base::ReadUnalignedValue<T>(reinterpret_cast<Address>(next_));
276 next_ += sizeof(result);
277 return result;
278 }
279
280 const uint8_t* start_;
281 const uint8_t* next_;
282 const uint8_t* end_;
283};
284
285#ifdef ENABLE_DISASSEMBLER
286
287class EhFrameDisassembler final {
288 public:
289 EhFrameDisassembler(const uint8_t* start, const uint8_t* end)
290 : start_(start), end_(end) {
292 }
293 EhFrameDisassembler(const EhFrameDisassembler&) = delete;
294 EhFrameDisassembler& operator=(const EhFrameDisassembler&) = delete;
295
296 void DisassembleToStream(std::ostream& stream);
297
298 private:
299 static void DumpDwarfDirectives(std::ostream& stream, const uint8_t* start,
300 const uint8_t* end);
301
302 static const char* DwarfRegisterCodeToString(int code);
303
304 const uint8_t* start_;
305 const uint8_t* end_;
306};
307
308#endif
309
310} // namespace internal
311} // namespace v8
312
313#endif // V8_DIAGNOSTICS_EH_FRAME_H_
static const int kDataAlignmentFactor
Definition eh-frame.h:63
static const int kCodeAlignmentFactor
Definition eh-frame.h:62
EhFrameIterator(const uint8_t *start, const uint8_t *end)
Definition eh-frame.h:215
const void * current_address() const
Definition eh-frame.h:261
EhFrameConstants::DwarfOpcodes GetNextOpcode()
Definition eh-frame.h:242
void Skip(int how_many)
Definition eh-frame.h:233
int GetProcedureAddressOffset() const
Definition eh-frame.h:181
void WriteBytes(const uint8_t *start, int size)
Definition eh-frame.h:145
void WriteOpcode(EhFrameConstants::DwarfOpcodes opcode)
Definition eh-frame.h:142
void IncreaseBaseAddressOffset(int base_delta)
Definition eh-frame.h:97
void WriteByte(uint8_t value)
Definition eh-frame.h:141
EhFrameWriter(const EhFrameWriter &)=delete
void PatchInt32(int base_offset, uint32_t value)
Definition eh-frame.h:154
void WriteInt16(uint16_t value)
Definition eh-frame.h:148
ZoneVector< uint8_t > eh_frame_buffer_
Definition eh-frame.h:210
int GetProcedureSizeOffset() const
Definition eh-frame.h:185
InternalState writer_state_
Definition eh-frame.h:207
void RecordRegisterSavedToStack(Register name, int offset)
Definition eh-frame.h:104
EhFrameWriter & operator=(const EhFrameWriter &)=delete
Register base_register() const
Definition eh-frame.h:130
void WriteInt32(uint32_t value)
Definition eh-frame.h:151
uint8_t *const start_
Definition assembler.cc:131
const v8::base::TimeTicks end_
Definition sweeper.cc:54
int start
int end
int32_t offset
ZoneVector< RpoNumber > & result
int pc_offset
int WriteBytes(const char *filename, const uint8_t *bytes, int size, bool verbose)
Definition utils.cc:201
constexpr int kInt32Size
Definition globals.h:401
#define NON_EXPORTED_BASE(code)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_EXPORT_PRIVATE
Definition macros.h:460