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