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 AddRow()41 void AddRow() { 42 this->PushUint8(DW_LNS_copy); 43 } 44 AdvancePC(uint64_t absolute_address)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 AdvanceLine(int absolute_line)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 SetFile(int file)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 SetColumn(int column)77 void SetColumn(int column) { 78 this->PushUint8(DW_LNS_set_column); 79 this->PushUleb128(column); 80 } 81 NegateStmt()82 void NegateStmt() { 83 this->PushUint8(DW_LNS_negate_stmt); 84 } 85 SetBasicBlock()86 void SetBasicBlock() { 87 this->PushUint8(DW_LNS_set_basic_block); 88 } 89 SetPrologueEnd()90 void SetPrologueEnd() { 91 uses_dwarf3_features_ = true; 92 this->PushUint8(DW_LNS_set_prologue_end); 93 } 94 SetEpilogueBegin()95 void SetEpilogueBegin() { 96 uses_dwarf3_features_ = true; 97 this->PushUint8(DW_LNS_set_epilogue_begin); 98 } 99 SetISA(int isa)100 void SetISA(int isa) { 101 uses_dwarf3_features_ = true; 102 this->PushUint8(DW_LNS_set_isa); 103 this->PushUleb128(isa); 104 } 105 EndSequence()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. SetAddress(uint64_t absolute_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 DefineFile(const char * filename,int directory_index,int modification_time,int file_size)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. AddRow(uint64_t absolute_address,int absolute_line)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 GetCodeFactorBits()195 int GetCodeFactorBits() const { 196 return code_factor_bits_; 197 } 198 CurrentAddress()199 uint64_t CurrentAddress() const { 200 return current_address_; 201 } 202 CurrentFile()203 int CurrentFile() const { 204 return current_file_; 205 } 206 CurrentLine()207 int CurrentLine() const { 208 return current_line_; 209 } 210 GetPatchLocations()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: FactorCodeOffset(uint64_t offset)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