Home | History | Annotate | Download | only in dwarf
      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 "debug/dwarf/debug_frame_opcode_writer.h"
     23 #include "debug/dwarf/debug_info_entry_writer.h"
     24 #include "debug/dwarf/debug_line_opcode_writer.h"
     25 #include "debug/dwarf/dwarf_constants.h"
     26 #include "debug/dwarf/register.h"
     27 #include "debug/dwarf/writer.h"
     28 #include "utils/array_ref.h"
     29 
     30 namespace art {
     31 namespace 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.
     40 template<typename Vector>
     41 void 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.
     79 inline
     80 void 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.
    126 template<typename Vector>
    127 void 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 
    150 struct 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.
    158 template<typename Vector>
    159 void 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