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