Index: src/eh-frame.h |
diff --git a/src/eh-frame.h b/src/eh-frame.h |
index 75781acb502ee8f420e93b240e7515e6e9f7348d..ebb5bd1a1446d922b651e92667c0be4ea96b43bf 100644 |
--- a/src/eh-frame.h |
+++ b/src/eh-frame.h |
@@ -5,19 +5,250 @@ |
#ifndef V8_EH_FRAME_H_ |
#define V8_EH_FRAME_H_ |
-#include <cstdint> |
+#include "src/macro-assembler.h" |
namespace v8 { |
namespace internal { |
-class Code; |
+class EhFrameWriter { |
+ public: |
+ enum class DwarfOpcodes : byte { |
+ kNop = 0x00, |
+ kAdvanceLoc1 = 0x02, |
+ kAdvanceLoc2 = 0x03, |
+ kAdvanceLoc4 = 0x04, |
+ kSameValue = 0x08, |
+ kDefCfa = 0x0c, |
+ kDefCfaRegister = 0x0d, |
+ kDefCfaOffset = 0x0e, |
+ kOffsetExtendedSf = 0x11, |
+ }; |
+ |
+ enum DwarfEncodingSpecifiers : byte { |
+ kUData4 = 0x03, |
+ kSData4 = 0x0b, |
+ kPcRel = 0x10, |
+ kDataRel = 0x30, |
+ kOmit = 0xff, |
+ }; |
+ |
+ static const int kLocationTag = 1; |
+ static const int kLocationMask = 0x3f; |
+ static const int kLocationMaskSize = 6; |
+ |
+ static const int kSavedRegisterTag = 2; |
+ static const int kSavedRegisterMask = 0x3f; |
+ static const int kSavedRegisterMaskSize = 6; |
+ |
+ static const int kFollowInitialRuleTag = 3; |
+ static const int kFollowInitialRuleMask = 0x3f; |
+ static const int kFollowInitialRuleMaskSize = 6; |
+ |
+ static const int kProcedureAddressOffsetInFde = 2 * kInt32Size; |
+ static const int kProcedureSizeOffsetInFde = 3 * kInt32Size; |
+ |
+ static const int kInitialStateOffsetInCIE = 19; |
+ static const int kEhFrameTerminatorSize = 4; |
+ |
+ static const int kDataAlignmentFactor; |
+ |
+ EhFrameWriter(); |
+ |
+ void AdvanceLocation(int pc_offset); |
+ |
+ // The <base_address> is the one to which all <offset>s in SaveRegisterToStack |
+ // directives are relative. It is given by <base_register> + <base_offset>. |
+ void SetBaseAddressRegister(Register base_register); |
+ void SetBaseAddressOffset(int base_offset); |
+ void IncreaseBaseAddressOffset(int base_delta) { |
+ SetBaseAddressOffset(base_offset_ + base_delta); |
+ } |
+ void SetBaseAddressRegisterAndOffset(Register base_register, int base_offset); |
+ |
+ // Offset relative to <base address>, positive offsets go in the direction |
+ // of stack growth (downwards on all architectures we support). |
+ void RecordRegisterSavedToStack(Register name, int offset) { |
+ RecordRegisterSavedToStack(RegisterToDwarfCode(name), offset); |
+ } |
+ |
+ void RecordRegisterSavedToStack(Register name) { |
+ RecordRegisterSavedToStack(name, base_offset_); |
+ } |
+ |
+ void RecordRegisterIsValid(Register name); |
+ |
+ void RecordRegisterFollowsInitialRule(Register name); |
+ |
+ void Finish(int code_size); |
+ |
+ // Remember to call Finish() before GetEhFrame(). |
+ // |
+ // The EhFrameWriter instance owns the buffer pointed by |
+ // CodeDesc::unwinding_info, and must outlive any use of the CodeDesc. |
+ void GetEhFrame(CodeDesc* desc); |
+ |
+ int last_pc_offset() const { return last_pc_offset_; } |
+ Register base_register() const { return base_register_; } |
+ int base_offset() const { return base_offset_; } |
+ |
+ private: |
+ static const uint32_t kInt32Placeholder = 0xdeadc0de; |
+ |
+ static int RegisterToDwarfCode(Register name); |
+ |
+ void WriteSLEB128(int32_t value); |
+ void WriteULEB128(uint32_t value); |
+ |
+ void WriteByte(byte value) { eh_frame_buffer_.push_back(value); } |
+ void WriteOpcode(DwarfOpcodes opcode) { |
+ WriteByte(static_cast<byte>(opcode)); |
+ } |
+ void WriteBytes(const byte* start, int size) { |
+ eh_frame_buffer_.insert(eh_frame_buffer_.end(), start, start + size); |
+ } |
+ void WriteInt16(uint16_t value) { |
+ WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value)); |
+ } |
+ void WriteInt32(uint32_t value) { |
+ WriteBytes(reinterpret_cast<const byte*>(&value), sizeof(value)); |
+ } |
+ void PatchInt32(int base_offset, uint32_t value) { |
+ DCHECK_EQ(ReadUnalignedUInt32(eh_frame_buffer_.data() + base_offset), |
+ kInt32Placeholder); |
+ DCHECK_LT(base_offset + kInt32Size, eh_frame_offset()); |
+ WriteUnalignedUInt32(eh_frame_buffer_.data() + base_offset, value); |
+ } |
+ |
+ void WriteCIE(); |
Stefano Sanfilippo
2016/07/05 19:53:56
I am not sure how to describe these methods in a c
rmcilroy
2016/07/06 13:59:30
"Write the Common Information Entry header" is fin
Stefano Sanfilippo
2016/07/06 16:54:50
Comments added.
|
+ void WriteReturnAddressRegisterCode(); |
+ void WriteInitialStateInCIE(); |
+ void WriteFDEHeader(); |
+ void WritePaddingTo8ByteAlignment(); |
+ |
+ // Internal version that directly accepts a DWARF register code, needed for |
+ // handling pseudoregisters on some platforms, such as x64. |
+ void RecordRegisterSavedToStack(int register_code, int offset); |
+ |
+ int eh_frame_offset() const { |
+ return static_cast<int>(eh_frame_buffer_.size()); |
+ } |
+ |
+ int fde_offset() const { return cie_size_; } |
+ |
+ int procedure_address_offset() const { |
+ return fde_offset() + kProcedureAddressOffsetInFde; |
+ } |
+ |
+ int procedure_size_offset() const { |
+ return fde_offset() + kProcedureSizeOffsetInFde; |
+ } |
+ |
+ int cie_size_; |
+ int last_pc_offset_; |
+ bool eh_frame_finalised_; |
+ Register base_register_; |
+ int base_offset_; |
+ std::vector<byte> eh_frame_buffer_; |
+}; |
+ |
+class EhFrameIterator { |
+ public: |
+ explicit EhFrameIterator(EhFrameWriter* writer); |
+ |
+ EhFrameIterator(const byte* start, const byte* end) |
+ : start_(start), next_(start), end_(end) { |
+ DCHECK_LE(start, end); |
+ } |
+ |
+ void SkipCIE() { |
+ DCHECK_EQ(next_, start_); |
+ next_ += ReadUnalignedUInt32(next_) + kInt32Size; |
+ } |
+ |
+ void SkipToFDEDirectives() { |
+ SkipCIE(); |
+ // Skip the FDE header. |
+ Skip(4 * kInt32Size + 1); |
+ } |
+ |
+ void Skip(int how_many) { |
+ next_ += how_many; |
+ DCHECK_LE(next_, end_); |
+ } |
+ |
+ uint32_t GetNextUInt32() { return GetNextIntegral<uint32_t>(); } |
+ uint16_t GetNextUInt16() { return GetNextIntegral<uint16_t>(); } |
+ byte GetNextByte() { return GetNextIntegral<byte>(); } |
+ EhFrameWriter::DwarfOpcodes GetNextOpcode() { |
+ return static_cast<EhFrameWriter::DwarfOpcodes>(GetNextByte()); |
+ } |
+ |
+ uint32_t GetNextULEB128(); |
+ int32_t GetNextSLEB128(); |
+ |
+ bool ReachedEnd() const { |
+ DCHECK_LE(next_, end_); |
+ return next_ == end_; |
+ } |
+ |
+ const void* current_address() const { |
+ return reinterpret_cast<const void*>(next_); |
+ } |
+ int GetCurrentOffset() const { |
+ DCHECK_GE(next_, start_); |
+ return static_cast<int>(next_ - start_); |
+ } |
+ int GetBufferSize() { return static_cast<int>(end_ - start_); } |
+ |
+ private: |
+ static uint32_t DecodeULEB128(const byte* encoded, int* encoded_size); |
+ static int32_t DecodeSLEB128(const byte* encoded, int* encoded_size); |
+ |
+ template <typename T> |
+ T GetNextIntegral() { |
+ T result; |
+ DCHECK_LE(next_ + sizeof(result), end_); |
+ result = ReadUnalignedValue<T>(next_); |
+ next_ += sizeof(result); |
+ return result; |
+ } |
+ |
+ const byte* start_; |
+ const byte* next_; |
+ const byte* end_; |
+ |
+ friend class EhFrameIteratorTest; |
+}; |
+ |
+#ifdef ENABLE_DISASSEMBLER |
+ |
+class EhFrameDisassembler final { |
+ public: |
+ EhFrameDisassembler(const byte* start, const byte* end) |
+ : start_(start), end_(end) { |
+ DCHECK_LE(start, end); |
+ } |
+ |
+ void DisassembleToStream(std::ostream& stream); // NOLINT |
+ |
+ private: |
+ static void DumpDWARFDirectives(std::ostream& stream, // NOLINT |
+ const byte* start, const byte* end); |
+ |
+ static const char* DwarfRegisterCodeToString(int code); |
+ |
+ const byte* start_; |
+ const byte* end_; |
+}; |
+ |
+#endif |
class EhFrameHdr final { |
public: |
static const int kRecordSize = 20; |
- static const int kCIESize; |
- explicit EhFrameHdr(Code* code); |
+ EhFrameHdr(int code_size, int eh_frame_size, int cie_size); |
+ static EhFrameHdr CreateEmptyHeader(); |
int32_t offset_to_eh_frame() const { return offset_to_eh_frame_; } |
uint32_t lut_entries_number() const { return lut_entries_number_; } |
@@ -25,6 +256,10 @@ class EhFrameHdr final { |
int32_t offset_to_fde() const { return offset_to_fde_; } |
private: |
+ static const int kEhFrameHdrVersion = 1; |
+ |
+ EhFrameHdr() {} |
+ |
uint8_t version_; |
uint8_t eh_frame_ptr_encoding_; |
uint8_t lut_size_encoding_; |