1 
2 /*
3  * Copyright (c) 2023 Huawei Device Co., Ltd.
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 #ifndef DFX_DWARF_EXPRESSION_H
17 #define DFX_DWARF_EXPRESSION_H
18 
19 #include <cinttypes>
20 #include <deque>
21 #include <type_traits>
22 #include <memory>
23 #include "dfx_errors.h"
24 #include "dfx_instr_statistic.h"
25 #include "dfx_memory.h"
26 #include "dfx_regs.h"
27 #include "dfx_regs_qut.h"
28 #include "dwarf_cfa_instructions.h"
29 
30 namespace OHOS {
31 namespace HiviewDFX {
32 // DWARF expressions describe how to compute a value or specify a location.
33 // They 2 are expressed in terms of DWARF operations that operate on a stack of values
34 template <typename AddressType>
35 class DwarfOp {
36     using SignedType = typename std::make_signed<AddressType>::type;
37     using UnsignedType = typename std::make_unsigned<AddressType>::type;
38 
39 public:
DwarfOp(std::shared_ptr<DfxMemory> memory)40     DwarfOp(std::shared_ptr<DfxMemory> memory) : memory_(memory) {};
41     virtual ~DwarfOp() = default;
42 
43     AddressType Eval(DfxRegs& regs, AddressType initStackValue, AddressType startPtr);
44 
45 protected:
46     bool Decode(DfxRegs& regs, uintptr_t& addr);
47 
StackReset(AddressType initialStackValue)48     inline void StackReset(AddressType initialStackValue)
49     {
50         stack_.clear();
51         stack_.push_front(initialStackValue);
52     };
53 
StackPush(AddressType value)54     inline void StackPush(AddressType value)
55     {
56         stack_.push_front(value);
57     }
58 
StackPop()59     inline AddressType StackPop()
60     {
61         AddressType value = stack_.front();
62         stack_.pop_front();
63         return value;
64     }
65 
StackAt(size_t index)66     inline AddressType StackAt(size_t index) { return stack_[index]; }
StackSize()67     inline size_t StackSize() { return stack_.size(); }
68 
69     /* DW_OP_addr DW_OP_constXs DW_OP_constXu */
70     template <typename T>
OpPush(T value)71     inline void OpPush(T value)
72     {
73         StackPush(static_cast<AddressType>(value));
74     };
75 
76     /* DW_OP_deref */
OpDeref()77     inline void OpDeref()
78     {
79         auto addr = static_cast<uintptr_t>(StackPop());
80         uintptr_t val;
81         memory_->ReadUptr(addr, &val);
82         StackPush(static_cast<AddressType>(val));
83     };
84 
85     /* DW_OP_deref_size */
OpDerefSize(AddressType & exprPtr)86     void OpDerefSize(AddressType& exprPtr)
87     {
88         auto addr = static_cast<uintptr_t>(StackPop());
89         AddressType value = 0;
90         uint8_t operand;
91         memory_->ReadU8(exprPtr, &operand, true);
92         switch (operand) {
93             case 1: { // 1 : read one byte length
94                 uint8_t u8;
95                 memory_->ReadU8(addr, &u8, true);
96                 value = static_cast<AddressType>(u8);
97             }
98                 break;
99             case 2: { // 2 : read two bytes length
100                 uint16_t u16;
101                 memory_->ReadU16(addr, &u16, true);
102                 value = static_cast<AddressType>(u16);
103             }
104                 break;
105             case 3: // 3 : read four bytes length
106             case 4: { // 4 : read four bytes length
107                 uint32_t u32;
108                 memory_->ReadU32(addr, &u32, true);
109                 value = static_cast<AddressType>(u32);
110             }
111                 break;
112             case 5: // 5 : read eight bytes length
113             case 6: // 6 : read eight bytes length
114             case 7: // 7 : read eight bytes length
115             case 8: { // 8 : read eight bytes length
116                 uint64_t u64;
117                 memory_->ReadU64(addr, &u64, true);
118                 value = static_cast<AddressType>(u64);
119             }
120                 break;
121             default:
122                 break;
123         }
124         StackPush(static_cast<UnsignedType>(value));
125     };
126 
127     /* DW_OP_dup */
OpDup()128     inline void OpDup()
129     {
130         StackPush(StackAt(0));
131     };
132 
133     /* DW_OP_drop */
OpDrop()134     inline void OpDrop()
135     {
136         StackPop();
137     };
138 
139     /* DW_OP_over */
OpOver()140     inline void OpOver()
141     {
142         StackPush(StackAt(1));
143     };
144 
145     /* DW_OP_pick */
OpPick(AddressType & exprPtr)146     inline void OpPick(AddressType& exprPtr)
147     {
148         uint8_t reg;
149         memory_->ReadU8(exprPtr, &reg, true);
150         if (reg > StackSize()) {
151             return;
152         }
153         AddressType value = StackAt(reg);
154         StackPush(value);
155     };
156 
157     /* DW_OP_swap */
OpSwap()158     inline void OpSwap()
159     {
160         AddressType oldValue = stack_[0];
161         stack_[0] = stack_[1];
162         stack_[1] = oldValue;
163     }
164 
165     /* DW_OP_rot */
OpRot()166     inline void OpRot()
167     {
168         AddressType top = stack_[0];
169         stack_[0] = stack_[1];
170         stack_[1] = stack_[2]; // 2:the index of the array
171         stack_[2] = top; // 2:the index of the array
172     }
173 
174     /* DW_OP_abs */
OpAbs()175     inline void OpAbs()
176     {
177         SignedType signedValue = static_cast<SignedType>(stack_[0]);
178         if (signedValue < 0) {
179             signedValue = -signedValue;
180         }
181         stack_[0] = static_cast<AddressType>(signedValue);
182     };
183 
184     /* DW_OP_and */
OpAnd()185     inline void OpAnd()
186     {
187         AddressType top = StackPop();
188         stack_[0] &= top;
189     };
190 
191     /* DW_OP_div */
OpDiv()192     inline void OpDiv()
193     {
194         AddressType top = StackPop();
195         if (top == 0) {
196             return;
197         }
198         SignedType signedDivisor = static_cast<SignedType>(top);
199         SignedType signedDividend = static_cast<SignedType>(stack_[0]);
200         stack_[0] = static_cast<AddressType>(signedDividend / signedDivisor);
201     };
202 
203     /* DW_OP_minus */
OpMinus()204     inline void OpMinus()
205     {
206         AddressType top = StackPop();
207         stack_[0] -= top;
208     };
209 
210     /* DW_OP_mod */
OpMod()211     inline void OpMod()
212     {
213         AddressType top = StackPop();
214         if (top == 0) {
215             return;
216         }
217         stack_[0] %= top;
218     };
219 
220     /* DW_OP_mul */
OpMul()221     inline void OpMul()
222     {
223         AddressType top = StackPop();
224         stack_[0] *= top;
225     };
226 
OpNeg()227     inline void OpNeg()
228     {
229         SignedType signedValue = static_cast<SignedType>(stack_[0]);
230         stack_[0] = static_cast<AddressType>(-signedValue);
231     };
232 
OpNot()233     inline void OpNot()
234     {
235         stack_[0] = ~stack_[0];
236     };
237 
OpOr()238     inline void OpOr()
239     {
240         AddressType top = StackPop();
241         stack_[0] |= top;
242     };
243 
OpPlus()244     inline void OpPlus()
245     {
246         AddressType top = StackPop();
247         stack_[0] += top;
248     };
249 
OpPlusULEBConst(AddressType & exprPtr)250     inline void OpPlusULEBConst(AddressType& exprPtr)
251     {
252         stack_[0] += memory_->ReadUleb128(exprPtr);
253     };
254 
OpShl()255     inline void OpShl()
256     {
257         AddressType top = StackPop();
258         stack_[0] <<= top;
259     };
260 
OpShr()261     inline void OpShr()
262     {
263         AddressType top = StackPop();
264         stack_[0] >>= top;
265     };
266 
OpShra()267     inline void OpShra()
268     {
269         AddressType top = StackPop();
270         SignedType signedValue = static_cast<SignedType>(stack_[0]) >> top;
271         stack_[0] = static_cast<AddressType>(signedValue);
272     };
273 
OpXor()274     inline void OpXor()
275     {
276         AddressType top = StackPop();
277         stack_[0] ^= top;
278     };
279 
OpSkip(AddressType & exprPtr)280     inline void OpSkip(AddressType& exprPtr)
281     {
282         int16_t offset;
283         memory_->ReadS16(exprPtr, &offset, true);
284         exprPtr = static_cast<AddressType>(exprPtr + offset);
285     };
286 
287     // DW_OP_bra
OpBra(AddressType & exprPtr)288     inline void OpBra(AddressType& exprPtr)
289     {
290         AddressType top = StackPop();
291         int16_t offset;
292         memory_->ReadS16(exprPtr, &offset, true);
293         if (top != 0) {
294             exprPtr = exprPtr + offset;
295         }
296     };
297 
OpEQ()298     inline void OpEQ()
299     {
300         AddressType top = StackPop();
301         stack_[0] = ((stack_[0] == top) ? 1 : 0);
302     };
303 
OpGE()304     inline void OpGE()
305     {
306         AddressType top = StackPop();
307         stack_[0] = ((stack_[0] >= top) ? 1 : 0);
308     };
309 
OpGT()310     inline void OpGT()
311     {
312         AddressType top = StackPop();
313         stack_[0] = ((stack_[0] > top) ? 1 : 0);
314     };
315 
OpLE()316     inline void OpLE()
317     {
318         AddressType top = StackPop();
319         stack_[0] = ((stack_[0] <= top) ? 1 : 0);
320     };
321 
OpLT()322     inline void OpLT()
323     {
324         AddressType top = StackPop();
325         stack_[0] = ((stack_[0] < top) ? 1 : 0);
326     };
327 
OpNE()328     inline void OpNE()
329     {
330         AddressType top = StackPop();
331         stack_[0] = ((stack_[0] != top) ? 1 : 0);
332     };
333 
334     // DW_OP_litXX
OpLit(uint8_t opcode)335     inline void OpLit(uint8_t opcode)
336     {
337         stack_.push_front(opcode - DW_OP_lit0);
338     };
339 
340     // DW_OP_regXX
OpReg(uint8_t opcode,DfxRegs & regs)341     inline void OpReg(uint8_t opcode, DfxRegs& regs)
342     {
343         auto reg = static_cast<UnsignedType>(opcode - DW_OP_reg0);
344         size_t qutIdx = 0;
345         if (!DfxRegsQut::IsQutReg(static_cast<uint16_t>(reg), qutIdx)) {
346             INSTR_STATISTIC(UnsupportedDwarfOp_Reg, reg, UNW_ERROR_UNSUPPORTED_QUT_REG);
347             return;
348         }
349         stack_.push_front(regs[reg]);
350     };
351 
352     // DW_OP_regx
OpRegx(AddressType & exprPtr,DfxRegs & regs)353     inline void OpRegx(AddressType& exprPtr, DfxRegs& regs)
354     {
355         auto reg = static_cast<uint32_t>(memory_->ReadUleb128(exprPtr));
356         size_t qutIdx = 0;
357         if (!DfxRegsQut::IsQutReg(static_cast<uint16_t>(reg), qutIdx)) {
358             INSTR_STATISTIC(UnsupportedDwarfOp_Regx, reg, UNW_ERROR_UNSUPPORTED_QUT_REG);
359             return;
360         }
361         stack_.push_front(regs[reg]);
362     };
363 
OpBReg(uint8_t opcode,AddressType & exprPtr,DfxRegs & regs)364     inline void OpBReg(uint8_t opcode, AddressType& exprPtr, DfxRegs& regs)
365     {
366         auto reg = static_cast<uint32_t>(opcode - DW_OP_breg0);
367         size_t qutIdx = 0;
368         if (!DfxRegsQut::IsQutReg(static_cast<uint16_t>(reg), qutIdx)) {
369             INSTR_STATISTIC(UnsupportedDwarfOp_Breg, reg, UNW_ERROR_UNSUPPORTED_QUT_REG);
370             return;
371         }
372         auto value = static_cast<SignedType>(memory_->ReadSleb128(exprPtr));
373         value += static_cast<SignedType>(regs[reg]);
374         stack_.push_front(value);
375     };
376 
OpBRegx(AddressType & exprPtr,DfxRegs & regs)377     inline void OpBRegx(AddressType& exprPtr, DfxRegs& regs)
378     {
379         auto reg = static_cast<uint32_t>(memory_->ReadUleb128(exprPtr));
380         size_t qutIdx = 0;
381         if (!DfxRegsQut::IsQutReg(static_cast<uint16_t>(reg), qutIdx)) {
382             INSTR_STATISTIC(UnsupportedDwarfOp_Bregx, reg, UNW_ERROR_UNSUPPORTED_QUT_REG);
383             return;
384         }
385         auto value = static_cast<SignedType>(memory_->ReadSleb128(exprPtr));
386         value += static_cast<SignedType>(regs[reg]);
387         stack_.push_front(value);
388     };
389 
OpNop(uint8_t opcode)390     inline void OpNop(uint8_t opcode)
391     {
392         // log un-implemmented operate codes
393     };
394 
395 protected:
396     std::shared_ptr<DfxMemory> memory_;
397     std::deque<AddressType> stack_;
398 };
399 } // nameapace HiviewDFX
400 } // nameapace OHOS
401 #endif