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