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/dwarf/debug_frame_opcode_writer.h"
24#include "debug/dwarf/dwarf_constants.h"
25#include "debug/dwarf/headers.h"
26#include "debug/method_debug_info.h"
27#include "elf_builder.h"
28
29namespace art {
30namespace debug {
31
32static void WriteCIE(InstructionSet isa,
33                     dwarf::CFIFormat format,
34                     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 kArm:
41    case 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, format, buffer);
62      return;
63    }
64    case 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, format, buffer);
85      return;
86    }
87    case kMips:
88    case 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, format, buffer);
109      return;
110    }
111    case 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, format, buffer);
135      return;
136    }
137    case 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, format, buffer);
161      return;
162    }
163    case kNone:
164      break;
165  }
166  LOG(FATAL) << "Cannot write CIE frame for ISA " << isa;
167  UNREACHABLE();
168}
169
170template<typename ElfTypes>
171void WriteCFISection(ElfBuilder<ElfTypes>* builder,
172                     const ArrayRef<const MethodDebugInfo>& method_infos,
173                     dwarf::CFIFormat format,
174                     bool write_oat_patches) {
175  CHECK(format == dwarf::DW_DEBUG_FRAME_FORMAT || format == dwarf::DW_EH_FRAME_FORMAT);
176  typedef typename ElfTypes::Addr Elf_Addr;
177
178  // The methods can be written in any order.
179  // Let's therefore sort them in the lexicographical order of the opcodes.
180  // This has no effect on its own. However, if the final .debug_frame section is
181  // compressed it reduces the size since similar opcodes sequences are grouped.
182  std::vector<const MethodDebugInfo*> sorted_method_infos;
183  sorted_method_infos.reserve(method_infos.size());
184  for (size_t i = 0; i < method_infos.size(); i++) {
185    if (!method_infos[i].cfi.empty() && !method_infos[i].deduped) {
186      sorted_method_infos.push_back(&method_infos[i]);
187    }
188  }
189  if (sorted_method_infos.empty()) {
190    return;
191  }
192  std::stable_sort(
193      sorted_method_infos.begin(),
194      sorted_method_infos.end(),
195      [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) {
196        ArrayRef<const uint8_t> l = lhs->cfi;
197        ArrayRef<const uint8_t> r = rhs->cfi;
198        return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
199      });
200
201  std::vector<uint32_t> binary_search_table;
202  std::vector<uintptr_t> patch_locations;
203  if (format == dwarf::DW_EH_FRAME_FORMAT) {
204    binary_search_table.reserve(2 * sorted_method_infos.size());
205  } else {
206    patch_locations.reserve(sorted_method_infos.size());
207  }
208
209  // Write .eh_frame/.debug_frame section.
210  auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT
211                       ? builder->GetDebugFrame()
212                       : builder->GetEhFrame());
213  {
214    cfi_section->Start();
215    const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
216    const Elf_Addr cfi_address = cfi_section->GetAddress();
217    const Elf_Addr cie_address = cfi_address;
218    Elf_Addr buffer_address = cfi_address;
219    std::vector<uint8_t> buffer;  // Small temporary buffer.
220    WriteCIE(builder->GetIsa(), format, &buffer);
221    cfi_section->WriteFully(buffer.data(), buffer.size());
222    buffer_address += buffer.size();
223    buffer.clear();
224    for (const MethodDebugInfo* mi : sorted_method_infos) {
225      DCHECK(!mi->deduped);
226      DCHECK(!mi->cfi.empty());
227      const Elf_Addr code_address = mi->code_address +
228          (mi->is_code_address_text_relative ? builder->GetText()->GetAddress() : 0);
229      if (format == dwarf::DW_EH_FRAME_FORMAT) {
230        binary_search_table.push_back(dchecked_integral_cast<uint32_t>(code_address));
231        binary_search_table.push_back(dchecked_integral_cast<uint32_t>(buffer_address));
232      }
233      WriteFDE(is64bit, cfi_address, cie_address,
234               code_address, mi->code_size,
235               mi->cfi, format, buffer_address, &buffer,
236               &patch_locations);
237      cfi_section->WriteFully(buffer.data(), buffer.size());
238      buffer_address += buffer.size();
239      buffer.clear();
240    }
241    cfi_section->End();
242  }
243
244  if (format == dwarf::DW_EH_FRAME_FORMAT) {
245    auto* header_section = builder->GetEhFrameHdr();
246    header_section->Start();
247    uint32_t header_address = dchecked_integral_cast<int32_t>(header_section->GetAddress());
248    // Write .eh_frame_hdr section.
249    std::vector<uint8_t> buffer;
250    dwarf::Writer<> header(&buffer);
251    header.PushUint8(1);  // Version.
252    // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
253    // so we have to use pcrel which means relative to the pointer's location.
254    header.PushUint8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4);
255    // Encoding of binary search table size.
256    header.PushUint8(dwarf::DW_EH_PE_udata4);
257    // Encoding of binary search table addresses - libunwind supports only this
258    // specific combination, which means relative to the start of .eh_frame_hdr.
259    header.PushUint8(dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4);
260    // .eh_frame pointer
261    header.PushInt32(cfi_section->GetAddress() - (header_address + 4u));
262    // Binary search table size (number of entries).
263    header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2));
264    header_section->WriteFully(buffer.data(), buffer.size());
265    // Binary search table.
266    for (size_t i = 0; i < binary_search_table.size(); i++) {
267      // Make addresses section-relative since we know the header address now.
268      binary_search_table[i] -= header_address;
269    }
270    header_section->WriteFully(binary_search_table.data(), binary_search_table.size());
271    header_section->End();
272  } else {
273    if (write_oat_patches) {
274      builder->WritePatches(".debug_frame.oat_patches",
275                            ArrayRef<const uintptr_t>(patch_locations));
276    }
277  }
278}
279
280}  // namespace debug
281}  // namespace art
282
283#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_
284
285