xref: /aosp_15_r20/art/libelffile/dwarf/debug_line_opcode_writer.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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