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_DWARF_HEADERS_H_ 18 #define ART_COMPILER_DWARF_HEADERS_H_ 19 20 #include <cstdint> 21 22 #include "dwarf/debug_frame_opcode_writer.h" 23 #include "dwarf/debug_info_entry_writer.h" 24 #include "dwarf/debug_line_opcode_writer.h" 25 #include "dwarf/dwarf_constants.h" 26 #include "dwarf/register.h" 27 #include "dwarf/writer.h" 28 29 namespace art { 30 namespace dwarf { 31 32 // Note that all headers start with 32-bit length. 33 // DWARF also supports 64-bit lengths, but we never use that. 34 // It is intended to support very large debug sections (>4GB), 35 // and compilers are expected *not* to use it by default. 36 // In particular, it is not related to machine architecture. 37 38 // Write common information entry (CIE) to .debug_frame or .eh_frame section. 39 template<typename Allocator> 40 void WriteDebugFrameCIE(bool is64bit, 41 ExceptionHeaderValueApplication address_type, 42 Reg return_address_register, 43 const DebugFrameOpCodeWriter<Allocator>& opcodes, 44 CFIFormat format, 45 std::vector<uint8_t>* debug_frame) { 46 Writer<> writer(debug_frame); 47 size_t cie_header_start_ = writer.data()->size(); 48 writer.PushUint32(0); // Length placeholder. 49 writer.PushUint32((format == DW_EH_FRAME_FORMAT) ? 0 : 0xFFFFFFFF); // CIE id. 50 writer.PushUint8(1); // Version. 51 writer.PushString("zR"); 52 writer.PushUleb128(DebugFrameOpCodeWriter<Allocator>::kCodeAlignmentFactor); 53 writer.PushSleb128(DebugFrameOpCodeWriter<Allocator>::kDataAlignmentFactor); 54 writer.PushUleb128(return_address_register.num()); // ubyte in DWARF2. 55 writer.PushUleb128(1); // z: Augmentation data size. 56 if (is64bit) { 57 if (address_type == DW_EH_PE_pcrel) { 58 writer.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata8); // R: Pointer encoding. 59 } else { 60 DCHECK(address_type == DW_EH_PE_absptr); 61 writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata8); // R: Pointer encoding. 62 } 63 } else { 64 if (address_type == DW_EH_PE_pcrel) { 65 writer.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4); // R: Pointer encoding. 66 } else { 67 DCHECK(address_type == DW_EH_PE_absptr); 68 writer.PushUint8(DW_EH_PE_absptr | DW_EH_PE_udata4); // R: Pointer encoding. 69 } 70 } 71 writer.PushData(opcodes.data()); 72 writer.Pad(is64bit ? 8 : 4); 73 writer.UpdateUint32(cie_header_start_, writer.data()->size() - cie_header_start_ - 4); 74 } 75 76 // Write frame description entry (FDE) to .debug_frame or .eh_frame section. 77 template<typename Allocator> 78 void WriteDebugFrameFDE(bool is64bit, size_t cie_offset, 79 uint64_t initial_address, uint64_t address_range, 80 const std::vector<uint8_t, Allocator>* opcodes, 81 CFIFormat format, 82 std::vector<uint8_t>* debug_frame, 83 std::vector<uintptr_t>* debug_frame_patches) { 84 Writer<> writer(debug_frame); 85 size_t fde_header_start = writer.data()->size(); 86 writer.PushUint32(0); // Length placeholder. 87 if (format == DW_EH_FRAME_FORMAT) { 88 uint32_t cie_pointer = writer.data()->size() - cie_offset; 89 writer.PushUint32(cie_pointer); 90 } else { 91 uint32_t cie_pointer = cie_offset; 92 writer.PushUint32(cie_pointer); 93 } 94 // Relocate initial_address, but not address_range (it is size). 95 debug_frame_patches->push_back(writer.data()->size()); 96 if (is64bit) { 97 writer.PushUint64(initial_address); 98 writer.PushUint64(address_range); 99 } else { 100 writer.PushUint32(initial_address); 101 writer.PushUint32(address_range); 102 } 103 writer.PushUleb128(0); // Augmentation data size. 104 writer.PushData(opcodes); 105 writer.Pad(is64bit ? 8 : 4); 106 writer.UpdateUint32(fde_header_start, writer.data()->size() - fde_header_start - 4); 107 } 108 109 // Write compilation unit (CU) to .debug_info section. 110 template<typename Allocator> 111 void WriteDebugInfoCU(uint32_t debug_abbrev_offset, 112 const DebugInfoEntryWriter<Allocator>& entries, 113 std::vector<uint8_t>* debug_info, 114 std::vector<uintptr_t>* debug_info_patches) { 115 Writer<> writer(debug_info); 116 size_t start = writer.data()->size(); 117 writer.PushUint32(0); // Length placeholder. 118 writer.PushUint16(3); // Version. 119 writer.PushUint32(debug_abbrev_offset); 120 writer.PushUint8(entries.Is64bit() ? 8 : 4); 121 size_t entries_offset = writer.data()->size(); 122 writer.PushData(entries.data()); 123 writer.UpdateUint32(start, writer.data()->size() - start - 4); 124 // Copy patch locations and make them relative to .debug_info section. 125 for (uintptr_t patch_location : entries.GetPatchLocations()) { 126 debug_info_patches->push_back(entries_offset + patch_location); 127 } 128 } 129 130 struct FileEntry { 131 std::string file_name; 132 int directory_index; 133 int modification_time; 134 int file_size; 135 }; 136 137 // Write line table to .debug_line section. 138 template<typename Allocator> 139 void WriteDebugLineTable(const std::vector<std::string>& include_directories, 140 const std::vector<FileEntry>& files, 141 const DebugLineOpCodeWriter<Allocator>& opcodes, 142 std::vector<uint8_t>* debug_line, 143 std::vector<uintptr_t>* debug_line_patches) { 144 Writer<> writer(debug_line); 145 size_t header_start = writer.data()->size(); 146 writer.PushUint32(0); // Section-length placeholder. 147 // Claim DWARF-2 version even though we use some DWARF-3 features. 148 // DWARF-2 consumers will ignore the unknown opcodes. 149 // This is what clang currently does. 150 writer.PushUint16(2); // .debug_line version. 151 size_t header_length_pos = writer.data()->size(); 152 writer.PushUint32(0); // Header-length placeholder. 153 writer.PushUint8(1 << opcodes.GetCodeFactorBits()); 154 writer.PushUint8(DebugLineOpCodeWriter<Allocator>::kDefaultIsStmt ? 1 : 0); 155 writer.PushInt8(DebugLineOpCodeWriter<Allocator>::kLineBase); 156 writer.PushUint8(DebugLineOpCodeWriter<Allocator>::kLineRange); 157 writer.PushUint8(DebugLineOpCodeWriter<Allocator>::kOpcodeBase); 158 static const int opcode_lengths[DebugLineOpCodeWriter<Allocator>::kOpcodeBase] = { 159 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 }; 160 for (int i = 1; i < DebugLineOpCodeWriter<Allocator>::kOpcodeBase; i++) { 161 writer.PushUint8(opcode_lengths[i]); 162 } 163 for (const std::string& directory : include_directories) { 164 writer.PushData(directory.data(), directory.size() + 1); 165 } 166 writer.PushUint8(0); // Terminate include_directories list. 167 for (const FileEntry& file : files) { 168 writer.PushData(file.file_name.data(), file.file_name.size() + 1); 169 writer.PushUleb128(file.directory_index); 170 writer.PushUleb128(file.modification_time); 171 writer.PushUleb128(file.file_size); 172 } 173 writer.PushUint8(0); // Terminate file list. 174 writer.UpdateUint32(header_length_pos, writer.data()->size() - header_length_pos - 4); 175 size_t opcodes_offset = writer.data()->size(); 176 writer.PushData(opcodes.data()); 177 writer.UpdateUint32(header_start, writer.data()->size() - header_start - 4); 178 // Copy patch locations and make them relative to .debug_line section. 179 for (uintptr_t patch_location : opcodes.GetPatchLocations()) { 180 debug_line_patches->push_back(opcodes_offset + patch_location); 181 } 182 } 183 184 } // namespace dwarf 185 } // namespace art 186 187 #endif // ART_COMPILER_DWARF_HEADERS_H_ 188