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_DEBUG_LINE_OPCODE_WRITER_H_
     18 #define ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
     19 
     20 #include <cstdint>
     21 
     22 #include "debug/dwarf/dwarf_constants.h"
     23 #include "debug/dwarf/writer.h"
     24 
     25 namespace art {
     26 namespace dwarf {
     27 
     28 // Writer for the .debug_line opcodes (DWARF-3).
     29 // The writer is very light-weight, however it will do the following for you:
     30 //  * Choose the most compact encoding of a given opcode.
     31 //  * Keep track of current state and convert absolute values to deltas.
     32 //  * Divide by header-defined factors as appropriate.
     33 template<typename Vector = std::vector<uint8_t>>
     34 class DebugLineOpCodeWriter FINAL : private Writer<Vector> {
     35   static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
     36 
     37  public:
     38   static constexpr int kOpcodeBase = 13;
     39   static constexpr bool kDefaultIsStmt = false;
     40   static constexpr int kLineBase = -5;
     41   static constexpr int kLineRange = 14;
     42 
     43   void AddRow() {
     44     this->PushUint8(DW_LNS_copy);
     45   }
     46 
     47   void AdvancePC(uint64_t absolute_address) {
     48     DCHECK_NE(current_address_, 0u);  // Use SetAddress for the first advance.
     49     DCHECK_GE(absolute_address, current_address_);
     50     if (absolute_address != current_address_) {
     51       uint64_t delta = FactorCodeOffset(absolute_address - current_address_);
     52       if (delta <= INT32_MAX) {
     53         this->PushUint8(DW_LNS_advance_pc);
     54         this->PushUleb128(static_cast<int>(delta));
     55         current_address_ = absolute_address;
     56       } else {
     57         SetAddress(absolute_address);
     58       }
     59     }
     60   }
     61 
     62   void AdvanceLine(int absolute_line) {
     63     int delta = absolute_line - current_line_;
     64     if (delta != 0) {
     65       this->PushUint8(DW_LNS_advance_line);
     66       this->PushSleb128(delta);
     67       current_line_ = absolute_line;
     68     }
     69   }
     70 
     71   void SetFile(int file) {
     72     if (current_file_ != file) {
     73       this->PushUint8(DW_LNS_set_file);
     74       this->PushUleb128(file);
     75       current_file_ = file;
     76     }
     77   }
     78 
     79   void SetColumn(int column) {
     80     this->PushUint8(DW_LNS_set_column);
     81     this->PushUleb128(column);
     82   }
     83 
     84   void SetIsStmt(bool is_stmt) {
     85     if (is_stmt_ != is_stmt) {
     86       this->PushUint8(DW_LNS_negate_stmt);
     87       is_stmt_ = is_stmt;
     88     }
     89   }
     90 
     91   void SetBasicBlock() {
     92     this->PushUint8(DW_LNS_set_basic_block);
     93   }
     94 
     95   void SetPrologueEnd() {
     96     uses_dwarf3_features_ = true;
     97     this->PushUint8(DW_LNS_set_prologue_end);
     98   }
     99 
    100   void SetEpilogueBegin() {
    101     uses_dwarf3_features_ = true;
    102     this->PushUint8(DW_LNS_set_epilogue_begin);
    103   }
    104 
    105   void SetISA(int isa) {
    106     uses_dwarf3_features_ = true;
    107     this->PushUint8(DW_LNS_set_isa);
    108     this->PushUleb128(isa);
    109   }
    110 
    111   void EndSequence() {
    112     this->PushUint8(0);
    113     this->PushUleb128(1);
    114     this->PushUint8(DW_LNE_end_sequence);
    115     current_address_ = 0;
    116     current_file_ = 1;
    117     current_line_ = 1;
    118     is_stmt_ = kDefaultIsStmt;
    119   }
    120 
    121   // Uncoditionally set address using the long encoding.
    122   // This gives the linker opportunity to relocate the address.
    123   void SetAddress(uint64_t absolute_address) {
    124     DCHECK_GE(absolute_address, current_address_);
    125     FactorCodeOffset(absolute_address);  // Check if it is factorable.
    126     this->PushUint8(0);
    127     if (use_64bit_address_) {
    128       this->PushUleb128(1 + 8);
    129       this->PushUint8(DW_LNE_set_address);
    130       patch_locations_.push_back(this->data()->size());
    131       this->PushUint64(absolute_address);
    132     } else {
    133       this->PushUleb128(1 + 4);
    134       this->PushUint8(DW_LNE_set_address);
    135       patch_locations_.push_back(this->data()->size());
    136       this->PushUint32(absolute_address);
    137     }
    138     current_address_ = absolute_address;
    139   }
    140 
    141   void DefineFile(const char* filename,
    142                   int directory_index,
    143                   int modification_time,
    144                   int file_size) {
    145     int size = 1 +
    146                strlen(filename) + 1 +
    147                UnsignedLeb128Size(directory_index) +
    148                UnsignedLeb128Size(modification_time) +
    149                UnsignedLeb128Size(file_size);
    150     this->PushUint8(0);
    151     this->PushUleb128(size);
    152     size_t start = data()->size();
    153     this->PushUint8(DW_LNE_define_file);
    154     this->PushString(filename);
    155     this->PushUleb128(directory_index);
    156     this->PushUleb128(modification_time);
    157     this->PushUleb128(file_size);
    158     DCHECK_EQ(start + size, data()->size());
    159   }
    160 
    161   // Compact address and line opcode.
    162   void AddRow(uint64_t absolute_address, int absolute_line) {
    163     DCHECK_GE(absolute_address, current_address_);
    164 
    165     // If the address is definitely too far, use the long encoding.
    166     uint64_t delta_address = FactorCodeOffset(absolute_address - current_address_);
    167     if (delta_address > UINT8_MAX) {
    168       AdvancePC(absolute_address);
    169       delta_address = 0;
    170     }
    171 
    172     // If the line is definitely too far, use the long encoding.
    173     int delta_line = absolute_line - current_line_;
    174     if (!(kLineBase <= delta_line && delta_line < kLineBase + kLineRange)) {
    175       AdvanceLine(absolute_line);
    176       delta_line = 0;
    177     }
    178 
    179     // Both address and line should be reasonable now.  Use the short encoding.
    180     int opcode = kOpcodeBase + (delta_line - kLineBase) +
    181                  (static_cast<int>(delta_address) * kLineRange);
    182     if (opcode > UINT8_MAX) {
    183       // If the address is still too far, try to increment it by const amount.
    184       int const_advance = (0xFF - kOpcodeBase) / kLineRange;
    185       opcode -= (kLineRange * const_advance);
    186       if (opcode <= UINT8_MAX) {
    187         this->PushUint8(DW_LNS_const_add_pc);
    188       } else {
    189         // Give up and use long encoding for address.
    190         AdvancePC(absolute_address);
    191         // Still use the opcode to do line advance and copy.
    192         opcode = kOpcodeBase + (delta_line - kLineBase);
    193       }
    194     }
    195     DCHECK(kOpcodeBase <= opcode && opcode <= 0xFF);
    196     this->PushUint8(opcode);  // Special opcode.
    197     current_line_ = absolute_line;
    198     current_address_ = absolute_address;
    199   }
    200 
    201   int GetCodeFactorBits() const {
    202     return code_factor_bits_;
    203   }
    204 
    205   uint64_t CurrentAddress() const {
    206     return current_address_;
    207   }
    208 
    209   int CurrentFile() const {
    210     return current_file_;
    211   }
    212 
    213   int CurrentLine() const {
    214     return current_line_;
    215   }
    216 
    217   const std::vector<uintptr_t>& GetPatchLocations() const {
    218     return patch_locations_;
    219   }
    220 
    221   using Writer<Vector>::data;
    222 
    223   DebugLineOpCodeWriter(bool use64bitAddress,
    224                         int codeFactorBits,
    225                         const typename Vector::allocator_type& alloc =
    226                             typename Vector::allocator_type())
    227       : Writer<Vector>(&opcodes_),
    228         opcodes_(alloc),
    229         uses_dwarf3_features_(false),
    230         use_64bit_address_(use64bitAddress),
    231         code_factor_bits_(codeFactorBits),
    232         current_address_(0),
    233         current_file_(1),
    234         current_line_(1),
    235         is_stmt_(kDefaultIsStmt) {
    236   }
    237 
    238  private:
    239   uint64_t FactorCodeOffset(uint64_t offset) const {
    240     DCHECK_GE(code_factor_bits_, 0);
    241     DCHECK_EQ((offset >> code_factor_bits_) << code_factor_bits_, offset);
    242     return offset >> code_factor_bits_;
    243   }
    244 
    245   Vector opcodes_;
    246   bool uses_dwarf3_features_;
    247   bool use_64bit_address_;
    248   int code_factor_bits_;
    249   uint64_t current_address_;
    250   int current_file_;
    251   int current_line_;
    252   bool is_stmt_;
    253   std::vector<uintptr_t> patch_locations_;
    254 
    255   DISALLOW_COPY_AND_ASSIGN(DebugLineOpCodeWriter);
    256 };
    257 
    258 }  // namespace dwarf
    259 }  // namespace art
    260 
    261 #endif  // ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
    262