Chromium Code Reviews| 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 |