1 /* 2 * Copyright (C) 2016 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_ELF_DEBUG_FRAME_WRITER_H_ 18 #define ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_ 19 20 #include <vector> 21 22 #include "arch/instruction_set.h" 23 #include "debug/method_debug_info.h" 24 #include "dwarf/debug_frame_opcode_writer.h" 25 #include "dwarf/dwarf_constants.h" 26 #include "dwarf/headers.h" 27 #include "elf/elf_builder.h" 28 29 namespace art { 30 namespace debug { 31 32 static constexpr bool kWriteDebugFrameHdr = false; 33 34 static void WriteCIE(InstructionSet isa, /*inout*/ std::vector<uint8_t>* buffer) { 35 using Reg = dwarf::Reg; 36 // Scratch registers should be marked as undefined. This tells the 37 // debugger that its value in the previous frame is not recoverable. 38 bool is64bit = Is64BitInstructionSet(isa); 39 switch (isa) { 40 case InstructionSet::kArm: 41 case InstructionSet::kThumb2: { 42 dwarf::DebugFrameOpCodeWriter<> opcodes; 43 opcodes.DefCFA(Reg::ArmCore(13), 0); // R13(SP). 44 // core registers. 45 for (int reg = 0; reg < 13; reg++) { 46 if (reg < 4 || reg == 12) { 47 opcodes.Undefined(Reg::ArmCore(reg)); 48 } else { 49 opcodes.SameValue(Reg::ArmCore(reg)); 50 } 51 } 52 // fp registers. 53 for (int reg = 0; reg < 32; reg++) { 54 if (reg < 16) { 55 opcodes.Undefined(Reg::ArmFp(reg)); 56 } else { 57 opcodes.SameValue(Reg::ArmFp(reg)); 58 } 59 } 60 auto return_reg = Reg::ArmCore(14); // R14(LR). 61 WriteCIE(is64bit, return_reg, opcodes, buffer); 62 return; 63 } 64 case InstructionSet::kArm64: { 65 dwarf::DebugFrameOpCodeWriter<> opcodes; 66 opcodes.DefCFA(Reg::Arm64Core(31), 0); // R31(SP). 67 // core registers. 68 for (int reg = 0; reg < 30; reg++) { 69 if (reg < 8 || reg == 16 || reg == 17) { 70 opcodes.Undefined(Reg::Arm64Core(reg)); 71 } else { 72 opcodes.SameValue(Reg::Arm64Core(reg)); 73 } 74 } 75 // fp registers. 76 for (int reg = 0; reg < 32; reg++) { 77 if (reg < 8 || reg >= 16) { 78 opcodes.Undefined(Reg::Arm64Fp(reg)); 79 } else { 80 opcodes.SameValue(Reg::Arm64Fp(reg)); 81 } 82 } 83 auto return_reg = Reg::Arm64Core(30); // R30(LR). 84 WriteCIE(is64bit, return_reg, opcodes, buffer); 85 return; 86 } 87 case InstructionSet::kMips: 88 case InstructionSet::kMips64: { 89 dwarf::DebugFrameOpCodeWriter<> opcodes; 90 opcodes.DefCFA(Reg::MipsCore(29), 0); // R29(SP). 91 // core registers. 92 for (int reg = 1; reg < 26; reg++) { 93 if (reg < 16 || reg == 24 || reg == 25) { // AT, V*, A*, T*. 94 opcodes.Undefined(Reg::MipsCore(reg)); 95 } else { 96 opcodes.SameValue(Reg::MipsCore(reg)); 97 } 98 } 99 // fp registers. 100 for (int reg = 0; reg < 32; reg++) { 101 if (reg < 24) { 102 opcodes.Undefined(Reg::Mips64Fp(reg)); 103 } else { 104 opcodes.SameValue(Reg::Mips64Fp(reg)); 105 } 106 } 107 auto return_reg = Reg::MipsCore(31); // R31(RA). 108 WriteCIE(is64bit, return_reg, opcodes, buffer); 109 return; 110 } 111 case InstructionSet::kX86: { 112 // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296 113 constexpr bool generate_opcodes_for_x86_fp = false; 114 dwarf::DebugFrameOpCodeWriter<> opcodes; 115 opcodes.DefCFA(Reg::X86Core(4), 4); // R4(ESP). 116 opcodes.Offset(Reg::X86Core(8), -4); // R8(EIP). 117 // core registers. 118 for (int reg = 0; reg < 8; reg++) { 119 if (reg <= 3) { 120 opcodes.Undefined(Reg::X86Core(reg)); 121 } else if (reg == 4) { 122 // Stack pointer. 123 } else { 124 opcodes.SameValue(Reg::X86Core(reg)); 125 } 126 } 127 // fp registers. 128 if (generate_opcodes_for_x86_fp) { 129 for (int reg = 0; reg < 8; reg++) { 130 opcodes.Undefined(Reg::X86Fp(reg)); 131 } 132 } 133 auto return_reg = Reg::X86Core(8); // R8(EIP). 134 WriteCIE(is64bit, return_reg, opcodes, buffer); 135 return; 136 } 137 case InstructionSet::kX86_64: { 138 dwarf::DebugFrameOpCodeWriter<> opcodes; 139 opcodes.DefCFA(Reg::X86_64Core(4), 8); // R4(RSP). 140 opcodes.Offset(Reg::X86_64Core(16), -8); // R16(RIP). 141 // core registers. 142 for (int reg = 0; reg < 16; reg++) { 143 if (reg == 4) { 144 // Stack pointer. 145 } else if (reg < 12 && reg != 3 && reg != 5) { // except EBX and EBP. 146 opcodes.Undefined(Reg::X86_64Core(reg)); 147 } else { 148 opcodes.SameValue(Reg::X86_64Core(reg)); 149 } 150 } 151 // fp registers. 152 for (int reg = 0; reg < 16; reg++) { 153 if (reg < 12) { 154 opcodes.Undefined(Reg::X86_64Fp(reg)); 155 } else { 156 opcodes.SameValue(Reg::X86_64Fp(reg)); 157 } 158 } 159 auto return_reg = Reg::X86_64Core(16); // R16(RIP). 160 WriteCIE(is64bit, return_reg, opcodes, buffer); 161 return; 162 } 163 case InstructionSet::kNone: 164 break; 165 } 166 LOG(FATAL) << "Cannot write CIE frame for ISA " << isa; 167 UNREACHABLE(); 168 } 169 170 template<typename ElfTypes> 171 void WriteCFISection(ElfBuilder<ElfTypes>* builder, 172 const ArrayRef<const MethodDebugInfo>& method_infos) { 173 typedef typename ElfTypes::Addr Elf_Addr; 174 175 // The methods can be written in any order. 176 // Let's therefore sort them in the lexicographical order of the opcodes. 177 // This has no effect on its own. However, if the final .debug_frame section is 178 // compressed it reduces the size since similar opcodes sequences are grouped. 179 std::vector<const MethodDebugInfo*> sorted_method_infos; 180 sorted_method_infos.reserve(method_infos.size()); 181 for (size_t i = 0; i < method_infos.size(); i++) { 182 if (!method_infos[i].cfi.empty() && !method_infos[i].deduped) { 183 sorted_method_infos.push_back(&method_infos[i]); 184 } 185 } 186 if (sorted_method_infos.empty()) { 187 return; 188 } 189 std::stable_sort( 190 sorted_method_infos.begin(), 191 sorted_method_infos.end(), 192 [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) { 193 ArrayRef<const uint8_t> l = lhs->cfi; 194 ArrayRef<const uint8_t> r = rhs->cfi; 195 return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); 196 }); 197 198 std::vector<uint32_t> binary_search_table; 199 if (kWriteDebugFrameHdr) { 200 binary_search_table.reserve(2 * sorted_method_infos.size()); 201 } 202 203 // Write .debug_frame section. 204 auto* cfi_section = builder->GetDebugFrame(); 205 { 206 cfi_section->Start(); 207 const bool is64bit = Is64BitInstructionSet(builder->GetIsa()); 208 std::vector<uint8_t> buffer; // Small temporary buffer. 209 WriteCIE(builder->GetIsa(), &buffer); 210 cfi_section->WriteFully(buffer.data(), buffer.size()); 211 buffer.clear(); 212 for (const MethodDebugInfo* mi : sorted_method_infos) { 213 DCHECK(!mi->deduped); 214 DCHECK(!mi->cfi.empty()); 215 const Elf_Addr code_address = mi->code_address + 216 (mi->is_code_address_text_relative ? builder->GetText()->GetAddress() : 0); 217 if (kWriteDebugFrameHdr) { 218 binary_search_table.push_back(dchecked_integral_cast<uint32_t>(code_address)); 219 binary_search_table.push_back(cfi_section->GetPosition()); 220 } 221 dwarf::WriteFDE(is64bit, 222 /* cie_pointer= */ 0, 223 code_address, 224 mi->code_size, 225 mi->cfi, 226 &buffer); 227 cfi_section->WriteFully(buffer.data(), buffer.size()); 228 buffer.clear(); 229 } 230 cfi_section->End(); 231 } 232 233 if (kWriteDebugFrameHdr) { 234 std::sort(binary_search_table.begin(), binary_search_table.end()); 235 236 // Custom Android section. It is very similar to the official .eh_frame_hdr format. 237 std::vector<uint8_t> header_buffer; 238 dwarf::Writer<> header(&header_buffer); 239 header.PushUint8(1); // Version. 240 header.PushUint8(dwarf::DW_EH_PE_omit); // Encoding of .eh_frame pointer - none. 241 header.PushUint8(dwarf::DW_EH_PE_udata4); // Encoding of binary search table size. 242 header.PushUint8(dwarf::DW_EH_PE_udata4); // Encoding of binary search table data. 243 header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2)); 244 245 auto* header_section = builder->GetDebugFrameHdr(); 246 header_section->Start(); 247 header_section->WriteFully(header_buffer.data(), header_buffer.size()); 248 header_section->WriteFully(binary_search_table.data(), binary_search_table.size()); 249 header_section->End(); 250 } 251 } 252 253 } // namespace debug 254 } // namespace art 255 256 #endif // ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_ 257 258