1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ART_COMPILER_DEBUG_DWARF_HEADERS_H_ 18#define ART_COMPILER_DEBUG_DWARF_HEADERS_H_ 19 20#include <cstdint> 21 22#include "base/array_ref.h" 23#include "debug/dwarf/debug_frame_opcode_writer.h" 24#include "debug/dwarf/debug_info_entry_writer.h" 25#include "debug/dwarf/debug_line_opcode_writer.h" 26#include "debug/dwarf/dwarf_constants.h" 27#include "debug/dwarf/register.h" 28#include "debug/dwarf/writer.h" 29 30namespace art { 31namespace dwarf { 32 33// Note that all headers start with 32-bit length. 34// DWARF also supports 64-bit lengths, but we never use that. 35// It is intended to support very large debug sections (>4GB), 36// and compilers are expected *not* to use it by default. 37// In particular, it is not related to machine architecture. 38 39// Write common information entry (CIE) to .debug_frame or .eh_frame section. 40template<typename Vector> 41void WriteCIE(bool is64bit, 42 Reg return_address_register, 43 const DebugFrameOpCodeWriter<Vector>& opcodes, 44 CFIFormat format, 45 std::vector<uint8_t>* buffer) { 46 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type"); 47 48 Writer<> writer(buffer); 49 size_t cie_header_start_ = writer.data()->size(); 50 writer.PushUint32(0); // Length placeholder. 51 writer.PushUint32((format == DW_EH_FRAME_FORMAT) ? 0 : 0xFFFFFFFF); // CIE id. 52 writer.PushUint8(1); // Version. 53 writer.PushString("zR"); 54 writer.PushUleb128(DebugFrameOpCodeWriter<Vector>::kCodeAlignmentFactor); 55 writer.PushSleb128(DebugFrameOpCodeWriter<Vector>::kDataAlignmentFactor); 56 writer.PushUleb128(return_address_register.num()); // ubyte in DWARF2. 57 writer.PushUleb128(1); // z: Augmentation data size. 58 if (is64bit) { 59 if (format == DW_EH_FRAME_FORMAT) { 60 writer.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata8); // R: Pointer encoding. 61 } else { 62 DCHECK(format == DW_DEBUG_FRAME_FORMAT); 63 writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata8); // R: Pointer encoding. 64 } 65 } else { 66 if (format == DW_EH_FRAME_FORMAT) { 67 writer.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); // R: Pointer encoding. 68 } else { 69 DCHECK(format == DW_DEBUG_FRAME_FORMAT); 70 writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata4); // R: Pointer encoding. 71 } 72 } 73 writer.PushData(opcodes.data()); 74 writer.Pad(is64bit ? 8 : 4); 75 writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4); 76} 77 78// Write frame description entry (FDE) to .debug_frame or .eh_frame section. 79inline 80void WriteFDE(bool is64bit, 81 uint64_t section_address, // Absolute address of the section. 82 uint64_t cie_address, // Absolute address of last CIE. 83 uint64_t code_address, 84 uint64_t code_size, 85 const ArrayRef<const uint8_t>& opcodes, 86 CFIFormat format, 87 uint64_t buffer_address, // Address of buffer in linked application. 88 std::vector<uint8_t>* buffer, 89 std::vector<uintptr_t>* patch_locations) { 90 CHECK_GE(cie_address, section_address); 91 CHECK_GE(buffer_address, section_address); 92 93 Writer<> writer(buffer); 94 size_t fde_header_start = writer.data()->size(); 95 writer.PushUint32(0); // Length placeholder. 96 if (format == DW_EH_FRAME_FORMAT) { 97 uint32_t cie_pointer = (buffer_address + buffer->size()) - cie_address; 98 writer.PushUint32(cie_pointer); 99 } else { 100 DCHECK(format == DW_DEBUG_FRAME_FORMAT); 101 uint32_t cie_pointer = cie_address - section_address; 102 writer.PushUint32(cie_pointer); 103 } 104 if (format == DW_EH_FRAME_FORMAT) { 105 // .eh_frame encodes the location as relative address. 106 code_address -= buffer_address + buffer->size(); 107 } else { 108 DCHECK(format == DW_DEBUG_FRAME_FORMAT); 109 // Relocate code_address if it has absolute value. 110 patch_locations->push_back(buffer_address + buffer->size() - section_address); 111 } 112 if (is64bit) { 113 writer.PushUint64(code_address); 114 writer.PushUint64(code_size); 115 } else { 116 writer.PushUint32(code_address); 117 writer.PushUint32(code_size); 118 } 119 writer.PushUleb128(0); // Augmentation data size. 120 writer.PushData(opcodes.data(), opcodes.size()); 121 writer.Pad(is64bit ? 8 : 4); 122 writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4); 123} 124 125// Write compilation unit (CU) to .debug_info section. 126template<typename Vector> 127void WriteDebugInfoCU(uint32_t debug_abbrev_offset, 128 const DebugInfoEntryWriter<Vector>& entries, 129 size_t debug_info_offset, // offset from start of .debug_info. 130 std::vector<uint8_t>* debug_info, 131 std::vector<uintptr_t>* debug_info_patches) { 132 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type"); 133 134 Writer<> writer(debug_info); 135 size_t start = writer.data()->size(); 136 writer.PushUint32(0); // Length placeholder. 137 writer.PushUint16(4); // Version. 138 writer.PushUint32(debug_abbrev_offset); 139 writer.PushUint8(entries.Is64bit() ? 8 : 4); 140 size_t entries_offset = writer.data()->size(); 141 DCHECK_EQ(entries_offset, DebugInfoEntryWriter<Vector>::kCompilationUnitHeaderSize); 142 writer.PushData(entries.data()); 143 writer.UpdateUint32(start, writer.data()->size() - start - 4); 144 // Copy patch locations and make them relative to .debug_info section. 145 for (uintptr_t patch_location : entries.GetPatchLocations()) { 146 debug_info_patches->push_back(debug_info_offset + entries_offset + patch_location); 147 } 148} 149 150struct FileEntry { 151 std::string file_name; 152 int directory_index; 153 int modification_time; 154 int file_size; 155}; 156 157// Write line table to .debug_line section. 158template<typename Vector> 159void WriteDebugLineTable(const std::vector<std::string>& include_directories, 160 const std::vector<FileEntry>& files, 161 const DebugLineOpCodeWriter<Vector>& opcodes, 162 size_t debug_line_offset, // offset from start of .debug_line. 163 std::vector<uint8_t>* debug_line, 164 std::vector<uintptr_t>* debug_line_patches) { 165 static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type"); 166 167 Writer<> writer(debug_line); 168 size_t header_start = writer.data()->size(); 169 writer.PushUint32(0); // Section-length placeholder. 170 writer.PushUint16(3); // .debug_line version. 171 size_t header_length_pos = writer.data()->size(); 172 writer.PushUint32(0); // Header-length placeholder. 173 writer.PushUint8(1 << opcodes.GetCodeFactorBits()); 174 writer.PushUint8(DebugLineOpCodeWriter<Vector>::kDefaultIsStmt ? 1 : 0); 175 writer.PushInt8(DebugLineOpCodeWriter<Vector>::kLineBase); 176 writer.PushUint8(DebugLineOpCodeWriter<Vector>::kLineRange); 177 writer.PushUint8(DebugLineOpCodeWriter<Vector>::kOpcodeBase); 178 static const int opcode_lengths[DebugLineOpCodeWriter<Vector>::kOpcodeBase] = { 179 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 }; 180 for (int i = 1; i < DebugLineOpCodeWriter<Vector>::kOpcodeBase; i++) { 181 writer.PushUint8(opcode_lengths[i]); 182 } 183 for (const std::string& directory : include_directories) { 184 writer.PushData(directory.data(), directory.size() + 1); 185 } 186 writer.PushUint8(0); // Terminate include_directories list. 187 for (const FileEntry& file : files) { 188 writer.PushData(file.file_name.data(), file.file_name.size() + 1); 189 writer.PushUleb128(file.directory_index); 190 writer.PushUleb128(file.modification_time); 191 writer.PushUleb128(file.file_size); 192 } 193 writer.PushUint8(0); // Terminate file list. 194 writer.UpdateUint32(header_length_pos, writer.data()->size() - header_length_pos - 4); 195 size_t opcodes_offset = writer.data()->size(); 196 writer.PushData(opcodes.data()); 197 writer.UpdateUint32(header_start, writer.data()->size() - header_start - 4); 198 // Copy patch locations and make them relative to .debug_line section. 199 for (uintptr_t patch_location : opcodes.GetPatchLocations()) { 200 debug_line_patches->push_back(debug_line_offset + opcodes_offset + patch_location); 201 } 202} 203 204} // namespace dwarf 205} // namespace art 206 207#endif // ART_COMPILER_DEBUG_DWARF_HEADERS_H_ 208