• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_LIBELFFILE_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
18  #define ART_LIBELFFILE_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 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  
AddRow()43    void AddRow() {
44      this->PushUint8(DW_LNS_copy);
45    }
46  
AdvancePC(uint64_t absolute_address)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  
AdvanceLine(int absolute_line)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  
SetFile(int file)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  
SetColumn(int column)79    void SetColumn(int column) {
80      this->PushUint8(DW_LNS_set_column);
81      this->PushUleb128(column);
82    }
83  
SetIsStmt(bool is_stmt)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  
SetBasicBlock()91    void SetBasicBlock() {
92      this->PushUint8(DW_LNS_set_basic_block);
93    }
94  
SetPrologueEnd()95    void SetPrologueEnd() {
96      uses_dwarf3_features_ = true;
97      this->PushUint8(DW_LNS_set_prologue_end);
98    }
99  
SetEpilogueBegin()100    void SetEpilogueBegin() {
101      uses_dwarf3_features_ = true;
102      this->PushUint8(DW_LNS_set_epilogue_begin);
103    }
104  
SetISA(int isa)105    void SetISA(int isa) {
106      uses_dwarf3_features_ = true;
107      this->PushUint8(DW_LNS_set_isa);
108      this->PushUleb128(isa);
109    }
110  
EndSequence()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.
SetAddress(uint64_t absolute_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  
DefineFile(const char * filename,int directory_index,int modification_time,int file_size)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.
AddRow(uint64_t absolute_address,int absolute_line)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  
GetCodeFactorBits()201    int GetCodeFactorBits() const {
202      return code_factor_bits_;
203    }
204  
CurrentAddress()205    uint64_t CurrentAddress() const {
206      return current_address_;
207    }
208  
CurrentFile()209    int CurrentFile() const {
210      return current_file_;
211    }
212  
CurrentLine()213    int CurrentLine() const {
214      return current_line_;
215    }
216  
GetPatchLocations()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:
FactorCodeOffset(uint64_t offset)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_LIBELFFILE_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
262