xref: /aosp_15_r20/art/libelffile/dwarf/debug_frame_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_FRAME_OPCODE_WRITER_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_LIBELFFILE_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
21*795d594fSAndroid Build Coastguard Worker #include "dwarf/dwarf_constants.h"
22*795d594fSAndroid Build Coastguard Worker #include "dwarf/register.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 .debug_frame opcodes (DWARF-3).
29*795d594fSAndroid Build Coastguard Worker // See the DWARF specification for the precise meaning of the opcodes.
30*795d594fSAndroid Build Coastguard Worker // The writer is very light-weight, however it will do the following for you:
31*795d594fSAndroid Build Coastguard Worker //  * Choose the most compact encoding of a given opcode.
32*795d594fSAndroid Build Coastguard Worker //  * Keep track of current state and convert absolute values to deltas.
33*795d594fSAndroid Build Coastguard Worker //  * Divide by header-defined factors as appropriate.
34*795d594fSAndroid Build Coastguard Worker template<typename Vector = std::vector<uint8_t> >
35*795d594fSAndroid Build Coastguard Worker class DebugFrameOpCodeWriter : private Writer<Vector> {
36*795d594fSAndroid Build Coastguard Worker   static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker  public:
39*795d594fSAndroid Build Coastguard Worker   // To save space, DWARF divides most offsets by header-defined factors.
40*795d594fSAndroid Build Coastguard Worker   // They are used in integer divisions, so we make them constants.
41*795d594fSAndroid Build Coastguard Worker   // We usually subtract from stack base pointer, so making the factor
42*795d594fSAndroid Build Coastguard Worker   // negative makes the encoded values positive and thus easier to encode.
43*795d594fSAndroid Build Coastguard Worker   static constexpr int kDataAlignmentFactor = -4;
44*795d594fSAndroid Build Coastguard Worker   static constexpr int kCodeAlignmentFactor = 1;
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker   // Explicitely advance the program counter to given location.
AdvancePC(int absolute_pc)47*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE AdvancePC(int absolute_pc) {
48*795d594fSAndroid Build Coastguard Worker     DCHECK_GE(absolute_pc, current_pc_);
49*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
50*795d594fSAndroid Build Coastguard Worker       int delta = FactorCodeOffset(absolute_pc - current_pc_);
51*795d594fSAndroid Build Coastguard Worker       if (delta != 0) {
52*795d594fSAndroid Build Coastguard Worker         if (delta <= 0x3F) {
53*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_advance_loc | delta);
54*795d594fSAndroid Build Coastguard Worker         } else if (delta <= UINT8_MAX) {
55*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_advance_loc1);
56*795d594fSAndroid Build Coastguard Worker           this->PushUint8(delta);
57*795d594fSAndroid Build Coastguard Worker         } else if (delta <= UINT16_MAX) {
58*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_advance_loc2);
59*795d594fSAndroid Build Coastguard Worker           this->PushUint16(delta);
60*795d594fSAndroid Build Coastguard Worker         } else {
61*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_advance_loc4);
62*795d594fSAndroid Build Coastguard Worker           this->PushUint32(delta);
63*795d594fSAndroid Build Coastguard Worker         }
64*795d594fSAndroid Build Coastguard Worker       }
65*795d594fSAndroid Build Coastguard Worker       current_pc_ = absolute_pc;
66*795d594fSAndroid Build Coastguard Worker     }
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker   // Override this method to automatically advance the PC before each opcode.
ImplicitlyAdvancePC()70*795d594fSAndroid Build Coastguard Worker   virtual void ImplicitlyAdvancePC() { }
71*795d594fSAndroid Build Coastguard Worker 
72*795d594fSAndroid Build Coastguard Worker   // Common alias in assemblers - spill relative to current stack pointer.
RelOffset(Reg reg,int offset)73*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE RelOffset(Reg reg, int offset) {
74*795d594fSAndroid Build Coastguard Worker     Offset(reg, offset - current_cfa_offset_);
75*795d594fSAndroid Build Coastguard Worker   }
76*795d594fSAndroid Build Coastguard Worker 
77*795d594fSAndroid Build Coastguard Worker   // Common alias in assemblers - increase stack frame size.
AdjustCFAOffset(int delta)78*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE AdjustCFAOffset(int delta) {
79*795d594fSAndroid Build Coastguard Worker     DefCFAOffset(current_cfa_offset_ + delta);
80*795d594fSAndroid Build Coastguard Worker   }
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker   // Custom alias - spill many registers based on bitmask.
RelOffsetForMany(Reg reg_base,int32_t offset,uint32_t reg_mask,int32_t reg_size)83*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE RelOffsetForMany(Reg reg_base,
84*795d594fSAndroid Build Coastguard Worker                                       int32_t offset,
85*795d594fSAndroid Build Coastguard Worker                                       uint32_t reg_mask,
86*795d594fSAndroid Build Coastguard Worker                                       int32_t reg_size) {
87*795d594fSAndroid Build Coastguard Worker     DCHECK(reg_size == 4 || reg_size == 8);
88*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
89*795d594fSAndroid Build Coastguard Worker       for (int i = 0; reg_mask != 0u; reg_mask >>= 1, i++) {
90*795d594fSAndroid Build Coastguard Worker         // Skip zero bits and go to the set bit.
91*795d594fSAndroid Build Coastguard Worker         int num_zeros = CTZ(reg_mask);
92*795d594fSAndroid Build Coastguard Worker         i += num_zeros;
93*795d594fSAndroid Build Coastguard Worker         reg_mask >>= num_zeros;
94*795d594fSAndroid Build Coastguard Worker         RelOffset(Reg(reg_base.num() + i), offset);
95*795d594fSAndroid Build Coastguard Worker         offset += reg_size;
96*795d594fSAndroid Build Coastguard Worker       }
97*795d594fSAndroid Build Coastguard Worker     }
98*795d594fSAndroid Build Coastguard Worker   }
99*795d594fSAndroid Build Coastguard Worker 
100*795d594fSAndroid Build Coastguard Worker   // Custom alias - unspill many registers based on bitmask.
RestoreMany(Reg reg_base,uint32_t reg_mask)101*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE RestoreMany(Reg reg_base, uint32_t reg_mask) {
102*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
103*795d594fSAndroid Build Coastguard Worker       for (int i = 0; reg_mask != 0u; reg_mask >>= 1, i++) {
104*795d594fSAndroid Build Coastguard Worker         // Skip zero bits and go to the set bit.
105*795d594fSAndroid Build Coastguard Worker         int num_zeros = CTZ(reg_mask);
106*795d594fSAndroid Build Coastguard Worker         i += num_zeros;
107*795d594fSAndroid Build Coastguard Worker         reg_mask >>= num_zeros;
108*795d594fSAndroid Build Coastguard Worker         Restore(Reg(reg_base.num() + i));
109*795d594fSAndroid Build Coastguard Worker       }
110*795d594fSAndroid Build Coastguard Worker     }
111*795d594fSAndroid Build Coastguard Worker   }
112*795d594fSAndroid Build Coastguard Worker 
Nop()113*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE Nop() {
114*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
115*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_nop);
116*795d594fSAndroid Build Coastguard Worker     }
117*795d594fSAndroid Build Coastguard Worker   }
118*795d594fSAndroid Build Coastguard Worker 
Offset(Reg reg,int offset)119*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE Offset(Reg reg, int offset) {
120*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
121*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
122*795d594fSAndroid Build Coastguard Worker       int factored_offset = FactorDataOffset(offset);  // May change sign.
123*795d594fSAndroid Build Coastguard Worker       if (factored_offset >= 0) {
124*795d594fSAndroid Build Coastguard Worker         if (0 <= reg.num() && reg.num() <= 0x3F) {
125*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_offset | reg.num());
126*795d594fSAndroid Build Coastguard Worker           this->PushUleb128(factored_offset);
127*795d594fSAndroid Build Coastguard Worker         } else {
128*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_offset_extended);
129*795d594fSAndroid Build Coastguard Worker           this->PushUleb128(reg.num());
130*795d594fSAndroid Build Coastguard Worker           this->PushUleb128(factored_offset);
131*795d594fSAndroid Build Coastguard Worker         }
132*795d594fSAndroid Build Coastguard Worker       } else {
133*795d594fSAndroid Build Coastguard Worker         uses_dwarf3_features_ = true;
134*795d594fSAndroid Build Coastguard Worker         this->PushUint8(DW_CFA_offset_extended_sf);
135*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(reg.num());
136*795d594fSAndroid Build Coastguard Worker         this->PushSleb128(factored_offset);
137*795d594fSAndroid Build Coastguard Worker       }
138*795d594fSAndroid Build Coastguard Worker     }
139*795d594fSAndroid Build Coastguard Worker   }
140*795d594fSAndroid Build Coastguard Worker 
Restore(Reg reg)141*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE Restore(Reg reg) {
142*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
143*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
144*795d594fSAndroid Build Coastguard Worker       if (0 <= reg.num() && reg.num() <= 0x3F) {
145*795d594fSAndroid Build Coastguard Worker         this->PushUint8(DW_CFA_restore | reg.num());
146*795d594fSAndroid Build Coastguard Worker       } else {
147*795d594fSAndroid Build Coastguard Worker         this->PushUint8(DW_CFA_restore_extended);
148*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(reg.num());
149*795d594fSAndroid Build Coastguard Worker       }
150*795d594fSAndroid Build Coastguard Worker     }
151*795d594fSAndroid Build Coastguard Worker   }
152*795d594fSAndroid Build Coastguard Worker 
Undefined(Reg reg)153*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE Undefined(Reg reg) {
154*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
155*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
156*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_undefined);
157*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(reg.num());
158*795d594fSAndroid Build Coastguard Worker     }
159*795d594fSAndroid Build Coastguard Worker   }
160*795d594fSAndroid Build Coastguard Worker 
SameValue(Reg reg)161*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE SameValue(Reg reg) {
162*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
163*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
164*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_same_value);
165*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(reg.num());
166*795d594fSAndroid Build Coastguard Worker     }
167*795d594fSAndroid Build Coastguard Worker   }
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker   // The previous value of "reg" is stored in register "new_reg".
Register(Reg reg,Reg new_reg)170*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE Register(Reg reg, Reg new_reg) {
171*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
172*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
173*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_register);
174*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(reg.num());
175*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(new_reg.num());
176*795d594fSAndroid Build Coastguard Worker     }
177*795d594fSAndroid Build Coastguard Worker   }
178*795d594fSAndroid Build Coastguard Worker 
RememberState()179*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE RememberState() {
180*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
181*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
182*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_remember_state);
183*795d594fSAndroid Build Coastguard Worker     }
184*795d594fSAndroid Build Coastguard Worker   }
185*795d594fSAndroid Build Coastguard Worker 
RestoreState()186*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE RestoreState() {
187*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
188*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
189*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_restore_state);
190*795d594fSAndroid Build Coastguard Worker     }
191*795d594fSAndroid Build Coastguard Worker   }
192*795d594fSAndroid Build Coastguard Worker 
DefCFA(Reg reg,int offset)193*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE DefCFA(Reg reg, int offset) {
194*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
195*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
196*795d594fSAndroid Build Coastguard Worker       if (offset >= 0) {
197*795d594fSAndroid Build Coastguard Worker         this->PushUint8(DW_CFA_def_cfa);
198*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(reg.num());
199*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(offset);  // Non-factored.
200*795d594fSAndroid Build Coastguard Worker       } else {
201*795d594fSAndroid Build Coastguard Worker         uses_dwarf3_features_ = true;
202*795d594fSAndroid Build Coastguard Worker         this->PushUint8(DW_CFA_def_cfa_sf);
203*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(reg.num());
204*795d594fSAndroid Build Coastguard Worker         this->PushSleb128(FactorDataOffset(offset));
205*795d594fSAndroid Build Coastguard Worker       }
206*795d594fSAndroid Build Coastguard Worker     }
207*795d594fSAndroid Build Coastguard Worker     current_cfa_offset_ = offset;
208*795d594fSAndroid Build Coastguard Worker   }
209*795d594fSAndroid Build Coastguard Worker 
DefCFARegister(Reg reg)210*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE DefCFARegister(Reg reg) {
211*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
212*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
213*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_def_cfa_register);
214*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(reg.num());
215*795d594fSAndroid Build Coastguard Worker     }
216*795d594fSAndroid Build Coastguard Worker   }
217*795d594fSAndroid Build Coastguard Worker 
DefCFAOffset(int offset)218*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE DefCFAOffset(int offset) {
219*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
220*795d594fSAndroid Build Coastguard Worker       if (current_cfa_offset_ != offset) {
221*795d594fSAndroid Build Coastguard Worker         ImplicitlyAdvancePC();
222*795d594fSAndroid Build Coastguard Worker         if (offset >= 0) {
223*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_def_cfa_offset);
224*795d594fSAndroid Build Coastguard Worker           this->PushUleb128(offset);  // Non-factored.
225*795d594fSAndroid Build Coastguard Worker         } else {
226*795d594fSAndroid Build Coastguard Worker           uses_dwarf3_features_ = true;
227*795d594fSAndroid Build Coastguard Worker           this->PushUint8(DW_CFA_def_cfa_offset_sf);
228*795d594fSAndroid Build Coastguard Worker           this->PushSleb128(FactorDataOffset(offset));
229*795d594fSAndroid Build Coastguard Worker         }
230*795d594fSAndroid Build Coastguard Worker       }
231*795d594fSAndroid Build Coastguard Worker     }
232*795d594fSAndroid Build Coastguard Worker     // Uncoditional so that the user can still get and check the value.
233*795d594fSAndroid Build Coastguard Worker     current_cfa_offset_ = offset;
234*795d594fSAndroid Build Coastguard Worker   }
235*795d594fSAndroid Build Coastguard Worker 
ValOffset(Reg reg,int offset)236*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE ValOffset(Reg reg, int offset) {
237*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
238*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
239*795d594fSAndroid Build Coastguard Worker       uses_dwarf3_features_ = true;
240*795d594fSAndroid Build Coastguard Worker       int factored_offset = FactorDataOffset(offset);  // May change sign.
241*795d594fSAndroid Build Coastguard Worker       if (factored_offset >= 0) {
242*795d594fSAndroid Build Coastguard Worker         this->PushUint8(DW_CFA_val_offset);
243*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(reg.num());
244*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(factored_offset);
245*795d594fSAndroid Build Coastguard Worker       } else {
246*795d594fSAndroid Build Coastguard Worker         this->PushUint8(DW_CFA_val_offset_sf);
247*795d594fSAndroid Build Coastguard Worker         this->PushUleb128(reg.num());
248*795d594fSAndroid Build Coastguard Worker         this->PushSleb128(factored_offset);
249*795d594fSAndroid Build Coastguard Worker       }
250*795d594fSAndroid Build Coastguard Worker     }
251*795d594fSAndroid Build Coastguard Worker   }
252*795d594fSAndroid Build Coastguard Worker 
DefCFAExpression(uint8_t * expr,int expr_size)253*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE DefCFAExpression(uint8_t* expr, int expr_size) {
254*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
255*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
256*795d594fSAndroid Build Coastguard Worker       uses_dwarf3_features_ = true;
257*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_def_cfa_expression);
258*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(expr_size);
259*795d594fSAndroid Build Coastguard Worker       this->PushData(expr, expr_size);
260*795d594fSAndroid Build Coastguard Worker     }
261*795d594fSAndroid Build Coastguard Worker   }
262*795d594fSAndroid Build Coastguard Worker 
Expression(Reg reg,uint8_t * expr,int expr_size)263*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE Expression(Reg reg, uint8_t* expr, int expr_size) {
264*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
265*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
266*795d594fSAndroid Build Coastguard Worker       uses_dwarf3_features_ = true;
267*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_expression);
268*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(reg.num());
269*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(expr_size);
270*795d594fSAndroid Build Coastguard Worker       this->PushData(expr, expr_size);
271*795d594fSAndroid Build Coastguard Worker     }
272*795d594fSAndroid Build Coastguard Worker   }
273*795d594fSAndroid Build Coastguard Worker 
ValExpression(Reg reg,uint8_t * expr,int expr_size)274*795d594fSAndroid Build Coastguard Worker   void ALWAYS_INLINE ValExpression(Reg reg, uint8_t* expr, int expr_size) {
275*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(enabled_)) {
276*795d594fSAndroid Build Coastguard Worker       ImplicitlyAdvancePC();
277*795d594fSAndroid Build Coastguard Worker       uses_dwarf3_features_ = true;
278*795d594fSAndroid Build Coastguard Worker       this->PushUint8(DW_CFA_val_expression);
279*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(reg.num());
280*795d594fSAndroid Build Coastguard Worker       this->PushUleb128(expr_size);
281*795d594fSAndroid Build Coastguard Worker       this->PushData(expr, expr_size);
282*795d594fSAndroid Build Coastguard Worker     }
283*795d594fSAndroid Build Coastguard Worker   }
284*795d594fSAndroid Build Coastguard Worker 
IsEnabled()285*795d594fSAndroid Build Coastguard Worker   bool IsEnabled() const { return enabled_; }
286*795d594fSAndroid Build Coastguard Worker 
SetEnabled(bool value)287*795d594fSAndroid Build Coastguard Worker   void SetEnabled(bool value) {
288*795d594fSAndroid Build Coastguard Worker     enabled_ = value;
289*795d594fSAndroid Build Coastguard Worker     if (enabled_ && opcodes_.capacity() == 0u) {
290*795d594fSAndroid Build Coastguard Worker       opcodes_.reserve(kDefaultCapacity);
291*795d594fSAndroid Build Coastguard Worker     }
292*795d594fSAndroid Build Coastguard Worker   }
293*795d594fSAndroid Build Coastguard Worker 
GetCurrentPC()294*795d594fSAndroid Build Coastguard Worker   int GetCurrentPC() const { return current_pc_; }
295*795d594fSAndroid Build Coastguard Worker 
GetCurrentCFAOffset()296*795d594fSAndroid Build Coastguard Worker   int GetCurrentCFAOffset() const { return current_cfa_offset_; }
297*795d594fSAndroid Build Coastguard Worker 
SetCurrentCFAOffset(int offset)298*795d594fSAndroid Build Coastguard Worker   void SetCurrentCFAOffset(int offset) { current_cfa_offset_ = offset; }
299*795d594fSAndroid Build Coastguard Worker 
300*795d594fSAndroid Build Coastguard Worker   using Writer<Vector>::data;
301*795d594fSAndroid Build Coastguard Worker 
302*795d594fSAndroid Build Coastguard Worker   explicit DebugFrameOpCodeWriter(bool enabled = true,
303*795d594fSAndroid Build Coastguard Worker                                   const typename Vector::allocator_type& alloc =
304*795d594fSAndroid Build Coastguard Worker                                       typename Vector::allocator_type())
305*795d594fSAndroid Build Coastguard Worker       : Writer<Vector>(&opcodes_),
306*795d594fSAndroid Build Coastguard Worker         enabled_(false),
307*795d594fSAndroid Build Coastguard Worker         opcodes_(alloc),
308*795d594fSAndroid Build Coastguard Worker         current_cfa_offset_(0),
309*795d594fSAndroid Build Coastguard Worker         current_pc_(0),
310*795d594fSAndroid Build Coastguard Worker         uses_dwarf3_features_(false) {
311*795d594fSAndroid Build Coastguard Worker     SetEnabled(enabled);
312*795d594fSAndroid Build Coastguard Worker   }
313*795d594fSAndroid Build Coastguard Worker 
~DebugFrameOpCodeWriter()314*795d594fSAndroid Build Coastguard Worker   virtual ~DebugFrameOpCodeWriter() { }
315*795d594fSAndroid Build Coastguard Worker 
316*795d594fSAndroid Build Coastguard Worker  protected:
317*795d594fSAndroid Build Coastguard Worker   // Best guess based on couple of observed outputs.
318*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kDefaultCapacity = 32u;
319*795d594fSAndroid Build Coastguard Worker 
FactorDataOffset(int offset)320*795d594fSAndroid Build Coastguard Worker   int FactorDataOffset(int offset) const {
321*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(offset % kDataAlignmentFactor, 0);
322*795d594fSAndroid Build Coastguard Worker     return offset / kDataAlignmentFactor;
323*795d594fSAndroid Build Coastguard Worker   }
324*795d594fSAndroid Build Coastguard Worker 
FactorCodeOffset(int offset)325*795d594fSAndroid Build Coastguard Worker   int FactorCodeOffset(int offset) const {
326*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(offset % kCodeAlignmentFactor, 0);
327*795d594fSAndroid Build Coastguard Worker     return offset / kCodeAlignmentFactor;
328*795d594fSAndroid Build Coastguard Worker   }
329*795d594fSAndroid Build Coastguard Worker 
330*795d594fSAndroid Build Coastguard Worker   bool enabled_;  // If disabled all writes are no-ops.
331*795d594fSAndroid Build Coastguard Worker   Vector opcodes_;
332*795d594fSAndroid Build Coastguard Worker   int current_cfa_offset_;
333*795d594fSAndroid Build Coastguard Worker   int current_pc_;
334*795d594fSAndroid Build Coastguard Worker   bool uses_dwarf3_features_;
335*795d594fSAndroid Build Coastguard Worker 
336*795d594fSAndroid Build Coastguard Worker  private:
337*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(DebugFrameOpCodeWriter);
338*795d594fSAndroid Build Coastguard Worker };
339*795d594fSAndroid Build Coastguard Worker 
340*795d594fSAndroid Build Coastguard Worker }  // namespace dwarf
341*795d594fSAndroid Build Coastguard Worker }  // namespace art
342*795d594fSAndroid Build Coastguard Worker 
343*795d594fSAndroid Build Coastguard Worker #endif  // ART_LIBELFFILE_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
344