1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "dwarf_op.h"
17 #include <cstring>
18 #include "dfx_log.h"
19 
20 namespace OHOS {
21 namespace HiviewDFX {
22 namespace {
23 #undef LOG_DOMAIN
24 #undef LOG_TAG
25 #define LOG_DOMAIN 0xD002D11
26 #define LOG_TAG "DfxDwarfOp"
27 }
28 
29 template <typename AddressType>
Eval(DfxRegs & regs,AddressType initStackValue,AddressType startPtr)30 AddressType DwarfOp<AddressType>::Eval(DfxRegs& regs, AddressType initStackValue, AddressType startPtr)
31 {
32     LOGU("Eval: initStackValue=%" PRIuPTR ", startPtr=%" PRIuPTR "", initStackValue, startPtr);
33     StackReset(initStackValue);
34 
35     uintptr_t addr = startPtr;
36     uintptr_t length = memory_->ReadUleb128(addr);
37     uintptr_t end = addr + length;
38     while (addr < end) {
39         if (!Decode(regs, addr)) {
40             break;
41         }
42     }
43 
44     if (stack_.empty()) {
45         LOGE("%s", "Eval: stack empty");
46         return 0;
47     }
48     return static_cast<AddressType>(StackPop());
49 }
50 
51 template <typename AddressType>
Decode(DfxRegs & regs,uintptr_t & addr)52 bool DwarfOp<AddressType>::Decode(DfxRegs& regs, uintptr_t& addr)
53 {
54     uint8_t opcode;
55     memory_->ReadU8(addr, &opcode, true);
56     switch (opcode) {
57         case DW_OP_addr: {
58             LOGU("%s", "DW_OP_addr");
59             uintptr_t val;
60             memory_->ReadUptr(addr, &val, true);
61             OpPush(val);
62         }
63             break;
64         case DW_OP_deref:
65             LOGU("%s", "DW_OP_deref");
66             OpDeref();
67             break;
68         case DW_OP_const1u: {
69             LOGU("%s", "DW_OP_const1u");
70             uint8_t val;
71             memory_->ReadU8(addr, &val, true);
72             OpPush(val);
73         }
74             break;
75         case DW_OP_const1s: {
76             LOGU("%s", "DW_OP_const1s");
77             int8_t val;
78             memory_->ReadS8(addr, &val, true);
79             OpPush(val);
80         }
81             break;
82         case DW_OP_const2u: {
83             LOGU("%s", "DW_OP_const2u");
84             uint16_t val;
85             memory_->ReadU16(addr, &val, true);
86             OpPush(val);
87         }
88             break;
89         case DW_OP_const2s: {
90             LOGU("%s", "DW_OP_const2s");
91             int16_t val;
92             memory_->ReadS16(addr, &val, true);
93             OpPush(val);
94         }
95             break;
96         case DW_OP_const4u: {
97             LOGU("%s", "DW_OP_const4u");
98             uint32_t val;
99             memory_->ReadU32(addr, &val, true);
100             OpPush(val);
101         }
102             break;
103         case DW_OP_const4s: {
104             LOGU("%s", "DW_OP_const4s");
105             int32_t val;
106             memory_->ReadS32(addr, &val, true);
107             OpPush(val);
108         }
109             break;
110         case DW_OP_const8u: {
111             LOGU("%s", "DW_OP_const8u");
112             uint64_t val;
113             memory_->ReadU64(addr, &val, true);
114             OpPush(val);
115         }
116             break;
117         case DW_OP_const8s: {
118             LOGU("%s", "DW_OP_const8s");
119             int64_t val;
120             memory_->ReadS64(addr, &val, true);
121             OpPush(val);
122         }
123             break;
124         case DW_OP_constu:
125             LOGU("%s", "DW_OP_constu");
126             OpPush(memory_->ReadUleb128(addr));
127             break;
128         case DW_OP_consts:
129             LOGU("%s", "DW_OP_consts");
130             OpPush(memory_->ReadSleb128(addr));
131             break;
132         case DW_OP_dup:
133             LOGU("%s", "DW_OP_dup");
134             OpDup();
135             break;
136         case DW_OP_drop:
137             LOGU("%s", "DW_OP_drop");
138             OpDrop();
139             break;
140         case DW_OP_over:
141             LOGU("%s", "DW_OP_over");
142             OpOver();
143             break;
144         case DW_OP_pick:
145             LOGU("%s", "DW_OP_pick");
146             OpPick(addr);
147             break;
148         case DW_OP_swap:
149             LOGU("%s", "DW_OP_swap");
150             OpSwap();
151             break;
152         case DW_OP_rot:
153             LOGU("%s", "DW_OP_rot");
154             OpRot();
155             break;
156         case DW_OP_abs:
157             LOGU("%s", "DW_OP_abs");
158             OpAbs();
159             break;
160         case DW_OP_and:
161             LOGU("%s", "DW_OP_and");
162             OpAnd();
163             break;
164         case DW_OP_div:
165             LOGU("%s", "DW_OP_div");
166             OpDiv();
167             break;
168         case DW_OP_minus:
169             LOGU("%s", "DW_OP_minus");
170             OpMinus();
171             break;
172         case DW_OP_mod:
173             LOGU("%s", "DW_OP_mod");
174             OpMod();
175             break;
176         case DW_OP_mul:
177             LOGU("%s", "DW_OP_mul");
178             OpMul();
179             break;
180         case DW_OP_neg:
181             LOGU("%s", "DW_OP_neg");
182             OpNeg();
183             break;
184         case DW_OP_not:
185             LOGU("%s", "DW_OP_not");
186             OpNot();
187             break;
188         case DW_OP_or:
189             LOGU("%s", "DW_OP_or");
190             OpOr();
191             break;
192         case DW_OP_plus:
193             LOGU("%s", "DW_OP_plus");
194             OpPlus();
195             break;
196         case DW_OP_plus_uconst:
197             LOGU("%s", "DW_OP_plus_uconst");
198             OpPlusULEBConst(addr);
199             break;
200         case DW_OP_shl:
201             LOGU("%s", "DW_OP_shl");
202             OpShl();
203             break;
204         case DW_OP_shr:
205             LOGU("%s", "DW_OP_shr");
206             OpShr();
207             break;
208         case DW_OP_shra:
209             LOGU("%s", "DW_OP_shra");
210             OpShra();
211             break;
212         case DW_OP_xor:
213             LOGU("%s", "DW_OP_xor");
214             OpXor();
215             break;
216         case DW_OP_skip:
217             LOGU("%s", "DW_OP_skip");
218             OpSkip(addr);
219             break;
220         case DW_OP_bra:
221             LOGU("%s", "DW_OP_bra");
222             OpBra(addr);
223             break;
224         case DW_OP_eq:
225             LOGU("%s", "DW_OP_eq");
226             OpEQ();
227             break;
228         case DW_OP_ge:
229             LOGU("%s", "DW_OP_ge");
230             OpGE();
231             break;
232         case DW_OP_gt:
233             LOGU("%s", "DW_OP_gt");
234             OpGT();
235             break;
236         case DW_OP_le:
237             LOGU("%s", "DW_OP_le");
238             OpLE();
239             break;
240         case DW_OP_lt:
241             LOGU("%s", "DW_OP_lt");
242             OpLT();
243             break;
244         case DW_OP_ne:
245             LOGU("%s", "DW_OP_ne");
246             OpNE();
247             break;
248         case DW_OP_lit0:
249         case DW_OP_lit1:
250         case DW_OP_lit2:
251         case DW_OP_lit3:
252         case DW_OP_lit4:
253         case DW_OP_lit5:
254         case DW_OP_lit6:
255         case DW_OP_lit7:
256         case DW_OP_lit8:
257         case DW_OP_lit9:
258         case DW_OP_lit10:
259         case DW_OP_lit11:
260         case DW_OP_lit12:
261         case DW_OP_lit13:
262         case DW_OP_lit14:
263         case DW_OP_lit15:
264         case DW_OP_lit16:
265         case DW_OP_lit17:
266         case DW_OP_lit18:
267         case DW_OP_lit19:
268         case DW_OP_lit20:
269         case DW_OP_lit21:
270         case DW_OP_lit22:
271         case DW_OP_lit23:
272         case DW_OP_lit24:
273         case DW_OP_lit25:
274         case DW_OP_lit26:
275         case DW_OP_lit27:
276         case DW_OP_lit28:
277         case DW_OP_lit29:
278         case DW_OP_lit30:
279         case DW_OP_lit31:
280             LOGU("%s", "DW_OP_litXX");
281             OpLit(opcode);
282             break;
283         case DW_OP_reg0:
284         case DW_OP_reg1:
285         case DW_OP_reg2:
286         case DW_OP_reg3:
287         case DW_OP_reg4:
288         case DW_OP_reg5:
289         case DW_OP_reg6:
290         case DW_OP_reg7:
291         case DW_OP_reg8:
292         case DW_OP_reg9:
293         case DW_OP_reg10:
294         case DW_OP_reg11:
295         case DW_OP_reg12:
296         case DW_OP_reg13:
297         case DW_OP_reg14:
298         case DW_OP_reg15:
299         case DW_OP_reg16:
300         case DW_OP_reg17:
301         case DW_OP_reg18:
302         case DW_OP_reg19:
303         case DW_OP_reg20:
304         case DW_OP_reg21:
305         case DW_OP_reg22:
306         case DW_OP_reg23:
307         case DW_OP_reg24:
308         case DW_OP_reg25:
309         case DW_OP_reg26:
310         case DW_OP_reg27:
311         case DW_OP_reg28:
312         case DW_OP_reg29:
313         case DW_OP_reg30:
314         case DW_OP_reg31:
315             LOGU("%s", "DW_OP_regXX");
316             OpReg(opcode, regs);
317             break;
318         case DW_OP_regx:
319             LOGU("%s", "DW_OP_regx");
320             OpRegx(addr, regs);
321             break;
322         case DW_OP_breg0:
323         case DW_OP_breg1:
324         case DW_OP_breg2:
325         case DW_OP_breg3:
326         case DW_OP_breg4:
327         case DW_OP_breg5:
328         case DW_OP_breg6:
329         case DW_OP_breg7:
330         case DW_OP_breg8:
331         case DW_OP_breg9:
332         case DW_OP_breg10:
333         case DW_OP_breg11:
334         case DW_OP_breg12:
335         case DW_OP_breg13:
336         case DW_OP_breg14:
337         case DW_OP_breg15:
338         case DW_OP_breg16:
339         case DW_OP_breg17:
340         case DW_OP_breg18:
341         case DW_OP_breg19:
342         case DW_OP_breg20:
343         case DW_OP_breg21:
344         case DW_OP_breg22:
345         case DW_OP_breg23:
346         case DW_OP_breg24:
347         case DW_OP_breg25:
348         case DW_OP_breg26:
349         case DW_OP_breg27:
350         case DW_OP_breg28:
351         case DW_OP_breg29:
352         case DW_OP_breg30:
353         case DW_OP_breg31:
354             LOGU("%s", "DW_OP_bregXX");
355             OpBReg(opcode, addr, regs);
356             break;
357         case DW_OP_bregx:
358             LOGU("%s", "DW_OP_bregx");
359             OpBRegx(addr, regs);
360             break;
361         case DW_OP_deref_size:
362             LOGU("%s", "DW_OP_deref_size");
363             OpDerefSize(addr);
364             break;
365         case DW_OP_fbreg:
366         case DW_OP_piece:
367         case DW_OP_xderef:
368         case DW_OP_xderef_size:
369         case DW_OP_nop:
370         case DW_OP_push_object_address:
371         case DW_OP_call2:
372         case DW_OP_call4:
373         case DW_OP_call_ref:
374             LOGE("DWARF OpNop opcode: %x", opcode);
375             OpNop(opcode);
376             break;
377         default:
378             LOGE("DWARF Unexpected opcode: %x", opcode);
379             return false;
380     }
381     return true;
382 }
383 
384 // offline unwind should support both dwarf32 and dwarf64 ?
385 template class DwarfOp<uintptr_t>;
386 
387 }   // namespace HiviewDFX
388 }   // namespace OHOS
389