| Index: src/eh-frame.h
|
| diff --git a/src/eh-frame.h b/src/eh-frame.h
|
| index 75781acb502ee8f420e93b240e7515e6e9f7348d..6e703d429a9973ded8c5f9905c5d313bc71f031c 100644
|
| --- a/src/eh-frame.h
|
| +++ b/src/eh-frame.h
|
| @@ -5,36 +5,292 @@
|
| #ifndef V8_EH_FRAME_H_
|
| #define V8_EH_FRAME_H_
|
|
|
| -#include <cstdint>
|
| +#include "src/macro-assembler.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -class Code;
|
| +class EhFrameConstants final : public AllStatic {
|
| + 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;
|
| +
|
| + // Defined in eh-writer-<arch>.cc
|
| + static const int kCodeAlignmentFactor;
|
| + static const int kDataAlignmentFactor;
|
| +
|
| + static const int kFdeVersionSize = 1;
|
| + static const int kFdeEncodingSpecifiersSize = 3;
|
| +
|
| + static const int kEhFrameHdrVersion = 1;
|
| + static const int kEhFrameHdrSize = 20;
|
| +};
|
| +
|
| +class EhFrameWriter {
|
| + public:
|
| + explicit EhFrameWriter(Zone* zone);
|
| +
|
| + // The empty frame is a hack to trigger fp-based unwinding in Linux perf
|
| + // compiled with libunwind support when processing DWARF-based call graphs.
|
| + //
|
| + // It is effectively a valid eh_frame_hdr with an empty look up table.
|
| + //
|
| + static void WriteEmptyEhFrame(std::ostream& stream); // NOLINT
|
| +
|
| + // Write the CIE and FDE header. Call it before any other method.
|
| + void Initialize();
|
| +
|
| + 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>.
|
| + //
|
| + // The <base_offset> must be positive or 0.
|
| + //
|
| + 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);
|
| +
|
| + // Register saved at location <base_address> + <offset>.
|
| + // The <offset> must be a multiple of EhFrameConstants::kDataAlignment.
|
| + void RecordRegisterSavedToStack(Register name, int offset) {
|
| + RecordRegisterSavedToStack(RegisterToDwarfCode(name), offset);
|
| + }
|
| +
|
| + // The register has not been modified from the previous frame.
|
| + void RecordRegisterNotModified(Register name);
|
| +
|
| + // The register follows the rule defined in the CIE.
|
| + 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:
|
| + enum class InternalState { kUndefined, kInitialized, kFinalized };
|
| +
|
| + static const uint32_t kInt32Placeholder = 0xdeadc0de;
|
| +
|
| + void WriteSLeb128(int32_t value);
|
| + void WriteULeb128(uint32_t value);
|
| +
|
| + void WriteByte(byte value) { eh_frame_buffer_.push_back(value); }
|
| + void WriteOpcode(EhFrameConstants::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);
|
| + }
|
| +
|
| + // Write the common information entry, which includes encoding specifiers,
|
| + // alignment factors, the return address (pseudo) register code and the
|
| + // directives to construct the initial state of the unwinding table.
|
| + void WriteCie();
|
| +
|
| + // Write the header of the function data entry, containing a pointer to the
|
| + // correspondent CIE and the position and size of the associated routine.
|
| + void WriteFdeHeader();
|
| +
|
| + // Write the contents of the .eh_frame_hdr section, including encoding
|
| + // specifiers and the routine => FDE lookup table.
|
| + void WriteEhFrameHdr(int code_size);
|
| +
|
| + // Write nops until the size reaches a multiple of 8 bytes.
|
| + void WritePaddingToAlignedSize(int unpadded_size);
|
| +
|
| + // Internal version that directly accepts a DWARF register code, needed for
|
| + // handling pseudo-registers on some platforms.
|
| + void RecordRegisterSavedToStack(int register_code, int offset);
|
|
|
| -class EhFrameHdr final {
|
| + int GetProcedureAddressOffset() const {
|
| + return fde_offset() + EhFrameConstants::kProcedureAddressOffsetInFde;
|
| + }
|
| +
|
| + int GetProcedureSizeOffset() const {
|
| + return fde_offset() + EhFrameConstants::kProcedureSizeOffsetInFde;
|
| + }
|
| +
|
| + int eh_frame_offset() const {
|
| + return static_cast<int>(eh_frame_buffer_.size());
|
| + }
|
| +
|
| + int fde_offset() const { return cie_size_; }
|
| +
|
| + // Platform specific functions implemented in eh-frame-<arch>.cc
|
| +
|
| + static int RegisterToDwarfCode(Register name);
|
| +
|
| + // Write directives to build the initial state in the CIE.
|
| + void WriteInitialStateInCie();
|
| +
|
| + // Write the return address (pseudo) register code.
|
| + void WriteReturnAddressRegisterCode();
|
| +
|
| + int cie_size_;
|
| + int last_pc_offset_;
|
| + InternalState writer_state_;
|
| + Register base_register_;
|
| + int base_offset_;
|
| + ZoneVector<byte> eh_frame_buffer_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(EhFrameWriter);
|
| +};
|
| +
|
| +class EhFrameIterator {
|
| public:
|
| - static const int kRecordSize = 20;
|
| - static const int kCIESize;
|
| + 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(kDirectivesOffsetInFde);
|
| + }
|
| +
|
| + void Skip(int how_many) {
|
| + DCHECK_GE(how_many, 0);
|
| + next_ += how_many;
|
| + DCHECK_LE(next_, end_);
|
| + }
|
| +
|
| + uint32_t GetNextUInt32() { return GetNextValue<uint32_t>(); }
|
| + uint16_t GetNextUInt16() { return GetNextValue<uint16_t>(); }
|
| + byte GetNextByte() { return GetNextValue<byte>(); }
|
| + EhFrameConstants::DwarfOpcodes GetNextOpcode() {
|
| + return static_cast<EhFrameConstants::DwarfOpcodes>(GetNextByte());
|
| + }
|
| +
|
| + uint32_t GetNextULeb128();
|
| + int32_t GetNextSLeb128();
|
| +
|
| + bool Done() const {
|
| + DCHECK_LE(next_, end_);
|
| + return next_ == end_;
|
| + }
|
|
|
| - explicit EhFrameHdr(Code* code);
|
| + int GetCurrentOffset() const {
|
| + DCHECK_GE(next_, start_);
|
| + return static_cast<int>(next_ - start_);
|
| + }
|
|
|
| - int32_t offset_to_eh_frame() const { return offset_to_eh_frame_; }
|
| - uint32_t lut_entries_number() const { return lut_entries_number_; }
|
| - int32_t offset_to_procedure() const { return offset_to_procedure_; }
|
| - int32_t offset_to_fde() const { return offset_to_fde_; }
|
| + int GetBufferSize() { return static_cast<int>(end_ - start_); }
|
| +
|
| + const void* current_address() const {
|
| + return reinterpret_cast<const void*>(next_);
|
| + }
|
| +
|
| + private:
|
| + static const int kDirectivesOffsetInFde = 4 * kInt32Size + 1;
|
| +
|
| + static uint32_t DecodeULeb128(const byte* encoded, int* encoded_size);
|
| + static int32_t DecodeSLeb128(const byte* encoded, int* encoded_size);
|
| +
|
| + template <typename T>
|
| + T GetNextValue() {
|
| + 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_;
|
| +};
|
| +
|
| +#ifdef ENABLE_DISASSEMBLER
|
| +
|
| +class EhFrameDisassembler final {
|
| + public:
|
| + EhFrameDisassembler(const byte* start, const byte* end)
|
| + : start_(start), end_(end) {
|
| + DCHECK_LT(start, end);
|
| + }
|
| +
|
| + void DisassembleToStream(std::ostream& stream); // NOLINT
|
|
|
| private:
|
| - uint8_t version_;
|
| - uint8_t eh_frame_ptr_encoding_;
|
| - uint8_t lut_size_encoding_;
|
| - uint8_t lut_entries_encoding_;
|
| - int32_t offset_to_eh_frame_;
|
| - uint32_t lut_entries_number_;
|
| - int32_t offset_to_procedure_;
|
| - int32_t offset_to_fde_;
|
| + 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_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(EhFrameDisassembler);
|
| };
|
|
|
| +#endif
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|
|
|