/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_ #define ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_ #include "debug_frame_opcode_writer.h" #include "dwarf.h" #include "writer.h" namespace art { namespace dwarf { // Writer for the .eh_frame section (which extends .debug_frame specification). template> class DebugFrameWriter FINAL : private Writer { public: void WriteCIE(Reg return_address_register, const uint8_t* initial_opcodes, int initial_opcodes_size) { DCHECK(cie_header_start_ == ~0u); cie_header_start_ = this->data()->size(); if (use_64bit_address_) { // TODO: This is not related to being 64bit. this->PushUint32(0xffffffff); this->PushUint64(0); // Length placeholder. this->PushUint64(0); // CIE id. } else { this->PushUint32(0); // Length placeholder. this->PushUint32(0); // CIE id. } this->PushUint8(1); // Version. this->PushString("zR"); this->PushUleb128(DebugFrameOpCodeWriter::kCodeAlignmentFactor); this->PushSleb128(DebugFrameOpCodeWriter::kDataAlignmentFactor); this->PushUleb128(return_address_register.num()); // ubyte in DWARF2. this->PushUleb128(1); // z: Augmentation data size. if (use_64bit_address_) { this->PushUint8(0x04); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8). } else { this->PushUint8(0x03); // R: ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4). } this->PushData(initial_opcodes, initial_opcodes_size); this->Pad(use_64bit_address_ ? 8 : 4); if (use_64bit_address_) { this->UpdateUint64(cie_header_start_ + 4, this->data()->size() - cie_header_start_ - 12); } else { this->UpdateUint32(cie_header_start_, this->data()->size() - cie_header_start_ - 4); } } void WriteCIE(Reg return_address_register, const DebugFrameOpCodeWriter& opcodes) { WriteCIE(return_address_register, opcodes.data()->data(), opcodes.data()->size()); } void WriteFDE(uint64_t initial_address, uint64_t address_range, const uint8_t* unwind_opcodes, int unwind_opcodes_size) { DCHECK(cie_header_start_ != ~0u); size_t fde_header_start = this->data()->size(); if (use_64bit_address_) { // TODO: This is not related to being 64bit. this->PushUint32(0xffffffff); this->PushUint64(0); // Length placeholder. this->PushUint64(this->data()->size() - cie_header_start_); // 'CIE_pointer' } else { this->PushUint32(0); // Length placeholder. this->PushUint32(this->data()->size() - cie_header_start_); // 'CIE_pointer' } if (use_64bit_address_) { this->PushUint64(initial_address); this->PushUint64(address_range); } else { this->PushUint32(initial_address); this->PushUint32(address_range); } this->PushUleb128(0); // Augmentation data size. this->PushData(unwind_opcodes, unwind_opcodes_size); this->Pad(use_64bit_address_ ? 8 : 4); if (use_64bit_address_) { this->UpdateUint64(fde_header_start + 4, this->data()->size() - fde_header_start - 12); } else { this->UpdateUint32(fde_header_start, this->data()->size() - fde_header_start - 4); } } DebugFrameWriter(std::vector* buffer, bool use_64bit_address) : Writer(buffer), use_64bit_address_(use_64bit_address), cie_header_start_(~0u) { } private: bool use_64bit_address_; size_t cie_header_start_; DISALLOW_COPY_AND_ASSIGN(DebugFrameWriter); }; } // namespace dwarf } // namespace art #endif // ART_COMPILER_DWARF_DEBUG_FRAME_WRITER_H_