• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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 "exidx_entry_parser.h"
17 #include <securec.h>
18 
19 #include "dfx_define.h"
20 #include "dfx_regs.h"
21 #include "dfx_regs_qut.h"
22 #include "dfx_log.h"
23 #include "dfx_instr_statistic.h"
24 #include "dfx_util.h"
25 #include "string_printf.h"
26 
27 #if defined(__arm__)
28 
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 #undef LOG_DOMAIN
33 #undef LOG_TAG
34 #define LOG_DOMAIN 0xD002D11
35 #define LOG_TAG "DfxExidxEntryParser"
36 
37 #define ARM_EXIDX_CANT_UNWIND   0x00000001
38 #define ARM_EXIDX_COMPACT       0x80000000
39 #define ARM_EXTBL_OP_FINISH     0xb0
40 
41 static const uintptr_t FOUR_BYTE_OFFSET = 4;
42 static const int TWO_BIT_OFFSET = 2;
43 static const int FOUR_BIT_OFFSET = 4;
44 static const int SEVEN_BIT_OFFSET = 7;
45 static const int EIGHT_BIT_OFFSET = 8;
46 static const int SIXTEEN_BIT_OFFSET = 16;
47 static const int TWENTY_FOUR_BIT_OFFSET = 24;
48 static const int TWENTY_EIGHT_BIT_OFFSET = 28;
49 }
50 
Reset(size_t size)51 void ExidxContext::Reset(size_t size)
52 {
53     vsp = 0;
54     transformedBits = 0;
55     if (size != 0) {
56         regs.resize(size);
57     }
58     for (size_t i = 0; i < regs.size(); ++i) {
59         regs[i] = 0;
60     }
61 }
62 
Transform(uint32_t reg)63 void ExidxContext::Transform(uint32_t reg)
64 {
65     DFXLOGU("Transform reg: %{public}d", reg);
66     transformedBits = transformedBits | (1 << reg);
67 }
68 
IsTransformed(uint32_t reg)69 bool ExidxContext::IsTransformed(uint32_t reg)
70 {
71     if (transformedBits & (1 << reg)) {
72         return true;
73     }
74     return false;
75 }
76 
AddUpVsp(int32_t imm)77 void ExidxContext::AddUpVsp(int32_t imm)
78 {
79     DFXLOGU("AddUpVsp imm: %{public}d", imm);
80     vsp += imm;
81 
82     auto qutRegs = DfxRegsQut::GetQutRegs();
83     for (size_t i = 0; i < qutRegs.size(); i++) {
84         uint32_t reg = static_cast<uint32_t>(qutRegs[i]);
85         if (IsTransformed(reg)) {
86             regs[i] += imm;
87         }
88     }
89 }
90 
FlushInstr()91 void ExidxEntryParser::FlushInstr()
92 {
93     if (rsState_->cfaReg == 0) {
94         rsState_->cfaReg = REG_SP;
95     }
96     rsState_->cfaRegOffset = 0;
97     if (context_.vsp != 0) {
98         if (__builtin_expect(!((context_.vsp & 0x3) == 0), false)) {
99             DFXLOGE("Check failed: context_.vsp & 0x3) == 0");
100         }
101         rsState_->cfaRegOffset = context_.vsp;
102     }
103     DFXLOGU("rsState cfaReg: %{public}d, cfaRegOffset: %{public}d", rsState_->cfaReg, rsState_->cfaRegOffset);
104 
105     auto qutRegs = DfxRegsQut::GetQutRegs();
106     for (size_t i = 0; i < qutRegs.size(); i++) {
107         uint32_t reg = static_cast<uint32_t>(qutRegs[i]);
108         if (context_.IsTransformed(reg)) {
109             if (__builtin_expect(!((context_.regs[i] & 0x3) == 0), false)) {
110                 DFXLOGE("Check failed: context_.regs[%{public}zu] & 0x3) == 0", i);
111             }
112             rsState_->locs[i].type = REG_LOC_MEM_OFFSET;
113             rsState_->locs[i].val = -context_.regs[i];
114             DFXLOGU("rsState reg: %{public}d, locs[%{public}d].val: %{public}d", reg, i, rsState_->locs[i].val);
115         }
116     }
117 
118     if (!isPcSet_) {
119         rsState_->returnAddressRegister = REG_LR;
120     } else {
121         rsState_->returnAddressRegister = REG_PC;
122     }
123 
124     context_.Reset();
125 }
126 
LogRawData()127 inline void ExidxEntryParser::LogRawData()
128 {
129     std::string logStr("Raw Data:");
130     for (const uint8_t data : ops_) {
131         logStr += StringPrintf(" 0x%02x", data);
132     }
133     DFXLOGU("%{public}s", logStr.c_str());
134 }
135 
SearchEntry(uintptr_t pc,const UnwindTableInfo & uti,struct UnwindEntryInfo & uei)136 bool ExidxEntryParser::SearchEntry(uintptr_t pc, const UnwindTableInfo &uti, struct UnwindEntryInfo& uei)
137 {
138     uintptr_t tableLen = uti.tableLen / ARM_EXIDX_TABLE_SIZE;
139     uintptr_t tableData = uti.tableData;
140     DFXLOGU("SearchEntry pc: %{public}p tableData: %{public}p, tableLen: %{public}u",
141         (void*)pc, (void*)tableData, (uint32_t)tableLen);
142     if (tableLen == 0) {
143         lastErrorData_.SetCode(UNW_ERROR_NO_UNWIND_INFO);
144         return false;
145     }
146 
147     // do binary search
148     uintptr_t entry = 0;
149     uintptr_t low = 0;
150     uintptr_t high = tableLen;
151     while (low < high) {
152         uintptr_t cur = (low + high) / 2; // 2 : binary search divided parameter
153         uintptr_t ptr = tableData + cur * ARM_EXIDX_TABLE_SIZE;
154         uintptr_t addr = 0;
155         if (!memory_->ReadPrel31(ptr, &addr)) {
156             lastErrorData_.SetAddrAndCode(ptr, UNW_ERROR_ILLEGAL_VALUE);
157             return false;
158         }
159 
160         if (pc == addr) {
161             entry = ptr;
162             break;
163         }
164         if (pc < addr) {
165             high = cur;
166         } else {
167             low = cur + 1;
168         }
169     }
170     if (entry == 0) {
171         if (high != 0) {
172             entry = tableData + (high - 1) * ARM_EXIDX_TABLE_SIZE;
173         } else {
174             lastErrorData_.SetCode(UNW_ERROR_NO_UNWIND_INFO);
175             return false;
176         }
177     }
178 
179     uei.unwindInfoSize = ARM_EXIDX_TABLE_SIZE;
180     uei.unwindInfo = (void *) entry;
181     uei.format = UNW_INFO_FORMAT_ARM_EXIDX;
182     return true;
183 }
184 
ExtractEntryData(uintptr_t entryOffset)185 bool ExidxEntryParser::ExtractEntryData(uintptr_t entryOffset)
186 {
187     DFXLOGU("Exidx entryOffset: %{public}llx", (uint64_t)entryOffset);
188     ops_.clear();
189     uint32_t data = 0;
190     if (entryOffset & 1) {
191         DFXLOGE("[%{public}d]: entryOffset: %{public}llx error.", __LINE__, (uint64_t)entryOffset);
192         lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_INVALID_ALIGNMENT);
193         return false;
194     }
195 
196     entryOffset += FOUR_BYTE_OFFSET;
197     if (!memory_->Read<uint32_t>(entryOffset, &data, false)) {
198         DFXLOGE("[%{public}d]: entryOffset: %{public}llx error.", __LINE__, (uint64_t)entryOffset);
199         lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_ILLEGAL_VALUE);
200         return false;
201     }
202 
203     if (data == ARM_EXIDX_CANT_UNWIND) {
204         DFXLOGU("This is a CANT UNWIND entry, data: %{public}x.", data);
205         lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_CANT_UNWIND);
206         return false;
207     } else if ((data & ARM_EXIDX_COMPACT) != 0) {
208         if (((data >> TWENTY_FOUR_BIT_OFFSET) & 0x7f) != 0) {
209             DFXLOGE("This is a non-zero index, this code doesn't support other formats.");
210             lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
211             return false;
212         }
213         DFXLOGU("This is a compact table entry, data: %{public}x.", data);
214         ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
215         ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
216         uint8_t lastOp = data & 0xff;
217         ops_.push_back(lastOp);
218         if (lastOp != ARM_EXTBL_OP_FINISH) {
219             ops_.push_back(ARM_EXTBL_OP_FINISH);
220         }
221         LogRawData();
222         return true;
223     }
224 
225     uintptr_t extabAddr = 0;
226     // prel31 decode point to .ARM.extab
227 #ifndef TEST_ARM_EXIDX
228     if (!memory_->ReadPrel31(entryOffset, &extabAddr)) {
229         lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_INVALID_MEMORY);
230         return false;
231     }
232 #else
233     extabAddr = entryOffset + FOUR_BYTE_OFFSET;
234 #endif
235     return ExtractEntryTab(extabAddr);
236 }
237 
ExtractEntryTabByPersonality(uintptr_t & tabOffset,uint32_t & data,uint8_t & tableCount)238 bool ExidxEntryParser::ExtractEntryTabByPersonality(uintptr_t& tabOffset, uint32_t& data, uint8_t& tableCount)
239 {
240     if ((data & ARM_EXIDX_COMPACT) == 0) {
241         DFXLOGU("Arm generic personality, data: %{public}x.", data);
242 #ifndef TEST_ARM_EXIDX
243         uintptr_t perRoutine;
244         if (!memory_->ReadPrel31(tabOffset, &perRoutine)) {
245             DFXLOGE("Arm Personality routine error");
246             lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
247             return false;
248         }
249 #endif
250 
251         tabOffset += FOUR_BYTE_OFFSET;
252         // Skip four bytes, because dont have unwind data to read
253         if (!memory_->Read<uint32_t>(tabOffset, &data, false)) {
254             lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
255             return false;
256         }
257         tableCount = (data >> TWENTY_FOUR_BIT_OFFSET) & 0xff;
258         ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
259         ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
260         ops_.push_back(data & 0xff);
261         tabOffset += FOUR_BYTE_OFFSET;
262     } else {
263         DFXLOGU("Arm compact personality, data: %{public}x.", data);
264         if ((data >> TWENTY_EIGHT_BIT_OFFSET) != 0x8) {
265             DFXLOGE("incorrect Arm compact model, [31:28]bit must be 0x8(%{public}x)",
266                 data >> TWENTY_EIGHT_BIT_OFFSET);
267             lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
268             return false;
269         }
270         uint8_t personality = (data >> TWENTY_FOUR_BIT_OFFSET) & 0x3;
271         if (personality > 2) { // 2 : personality must be 0 1 2
272             DFXLOGE("incorrect Arm compact personality(%{public}u)", personality);
273             lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
274             return false;
275         }
276         // inline compact model, when personality is 0
277         if (personality == 0) {
278             ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
279         } else if (personality == 1 || personality == 2) { // 2 : personality equal to 2
280             tableCount = (data >> SIXTEEN_BIT_OFFSET) & 0xff;
281             tabOffset += FOUR_BYTE_OFFSET;
282         }
283         ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
284         ops_.push_back(data & 0xff);
285     }
286     return true;
287 }
288 
ExtractEntryTab(uintptr_t tabOffset)289 bool ExidxEntryParser::ExtractEntryTab(uintptr_t tabOffset)
290 {
291     uint32_t data = 0;
292     DFXLOGU("Exidx tabOffset: %{public}llx", static_cast<uint64_t>(tabOffset));
293     if (!memory_->Read<uint32_t>(tabOffset, &data, false)) {
294         lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
295         return false;
296     }
297 
298     uint8_t tableCount = 0;
299     if (!ExtractEntryTabByPersonality(tabOffset, data, tableCount)) {
300         return false;
301     }
302 
303     if (tableCount > 5) { // 5 : 5 operators
304         lastErrorData_.SetCode(UNW_ERROR_NOT_SUPPORT);
305         return false;
306     }
307 
308     for (size_t i = 0; i < tableCount; i++) {
309         if (!memory_->Read<uint32_t>(tabOffset, &data, false)) {
310             return false;
311         }
312         tabOffset += FOUR_BYTE_OFFSET;
313         ops_.push_back((data >> TWENTY_FOUR_BIT_OFFSET) & 0xff);
314         ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
315         ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
316         ops_.push_back(data & 0xff);
317     }
318 
319     if (!ops_.empty() && ops_.back() != ARM_EXTBL_OP_FINISH) {
320         ops_.push_back(ARM_EXTBL_OP_FINISH);
321     }
322     LogRawData();
323     return true;
324 }
325 
GetOpCode()326 inline bool ExidxEntryParser::GetOpCode()
327 {
328     if (ops_.empty()) {
329         return false;
330     }
331     curOp_ = ops_.front();
332     ops_.pop_front();
333     DFXLOGU("curOp: %{public}llx", (uint64_t)curOp_);
334     return true;
335 }
336 
Eval(uintptr_t entryOffset)337 bool ExidxEntryParser::Eval(uintptr_t entryOffset)
338 {
339     if (!ExtractEntryData(entryOffset)) {
340         return false;
341     }
342 
343     DecodeTable decodeTable[] = {
344         {0xc0, 0x00, &ExidxEntryParser::Decode00xxxxxx},
345         {0xc0, 0x40, &ExidxEntryParser::Decode01xxxxxx},
346         {0xf0, 0x80, &ExidxEntryParser::Decode1000iiiiiiiiiiii},
347         {0xf0, 0x90, &ExidxEntryParser::Decode1001nnnn},
348         {0xf0, 0xa0, &ExidxEntryParser::Decode1010nnnn},
349         {0xff, 0xb0, &ExidxEntryParser::Decode10110000},
350         {0xff, 0xb1, &ExidxEntryParser::Decode101100010000iiii},
351         {0xff, 0xb2, &ExidxEntryParser::Decode10110010uleb128},
352         {0xff, 0xb3, &ExidxEntryParser::Decode10110011sssscccc},
353         {0xfc, 0xb4, &ExidxEntryParser::Decode101101nn},
354         {0xf8, 0xb8, &ExidxEntryParser::Decode10111nnn},
355         {0xff, 0xc6, &ExidxEntryParser::Decode11000110sssscccc},
356         {0xff, 0xc7, &ExidxEntryParser::Decode110001110000iiii},
357         {0xfe, 0xc8, &ExidxEntryParser::Decode1100100nsssscccc},
358         {0xc8, 0xc8, &ExidxEntryParser::Decode11001yyy},
359         {0xf8, 0xc0, &ExidxEntryParser::Decode11000nnn},
360         {0xf8, 0xd0, &ExidxEntryParser::Decode11010nnn},
361         {0xc0, 0xc0, &ExidxEntryParser::Decode11xxxyyy}
362     };
363     context_.Reset();
364     while (Decode(decodeTable, sizeof(decodeTable) / sizeof(decodeTable[0])));
365     return true;
366 }
367 
Step(uintptr_t pc,const UnwindTableInfo & uti,std::shared_ptr<RegLocState> rs)368 bool ExidxEntryParser::Step(uintptr_t pc, const UnwindTableInfo& uti, std::shared_ptr<RegLocState> rs)
369 {
370     if (memory_ == nullptr || rs == nullptr) {
371         DFXLOGE("memory or rs is nullptr");
372         return false;
373     }
374     rsState_ = rs;
375     UnwindEntryInfo uei;
376     if (!SearchEntry(pc, uti, uei)) {
377         DFXLOGE("Failed to search unwind entry");
378         return false;
379     }
380     uintptr_t entryOffset = reinterpret_cast<uintptr_t>(uei.unwindInfo);
381     if (!Eval(entryOffset)) {
382         return false;
383     }
384 
385     FlushInstr();
386     return true;
387 }
388 
DecodeSpare()389 inline bool ExidxEntryParser::DecodeSpare()
390 {
391     DFXLOGU("Exidx Decode Spare");
392     lastErrorData_.SetCode(UNW_ERROR_ARM_EXIDX_SPARE);
393     return false;
394 }
395 
Decode(DecodeTable decodeTable[],size_t size)396 bool ExidxEntryParser::Decode(DecodeTable decodeTable[], size_t size)
397 {
398     if (!GetOpCode()) {
399         return false;
400     }
401 
402     bool ret = false;
403     for (size_t i = 0; i < size; ++i) {
404         if ((curOp_ & decodeTable[i].mask) == decodeTable[i].result) {
405             if (decodeTable[i].decoder != nullptr) {
406                 DFXLOGU("decodeTable[%{public}d].mask: %{public}02x", i, decodeTable[i].mask);
407                 ret = (this->*(decodeTable[i].decoder))();
408                 break;
409             }
410         }
411     }
412     return ret;
413 }
414 
Decode00xxxxxx()415 inline bool ExidxEntryParser::Decode00xxxxxx()
416 {
417     // 00xxxxxx: vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
418     context_.AddUpVsp(((curOp_ & 0x3f) << 2) + 4);
419     return true;
420 }
421 
Decode01xxxxxx()422 inline bool ExidxEntryParser::Decode01xxxxxx()
423 {
424     // 01xxxxxx: vsp = vsp - (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive
425     context_.AddUpVsp(-(((curOp_ & 0x3f) << 2) + 4));
426     return true;
427 }
428 
Decode1000iiiiiiiiiiii()429 bool ExidxEntryParser::Decode1000iiiiiiiiiiii()
430 {
431     uint16_t registers = ((curOp_ & 0x0f) << 8);
432     if (!GetOpCode()) {
433         return false;
434     }
435     registers |= curOp_;
436     if (registers == 0x0) {
437         DFXLOGE("10000000 00000000: Refuse to unwind!");
438         lastErrorData_.SetCode(UNW_ERROR_CANT_UNWIND);
439         return false;
440     }
441 
442     registers <<= FOUR_BIT_OFFSET;
443     DFXLOGU("1000iiii iiiiiiii: registers: %{public}02x)", registers);
444     for (size_t reg = REG_ARM_R4; reg < REG_ARM_LAST; reg++) {
445         if ((registers & (1 << reg))) {
446             if (REG_PC == reg) {
447                 isPcSet_ = true;
448             }
449             context_.Transform(reg);
450             context_.AddUpVsp(FOUR_BYTE_OFFSET);
451         }
452     }
453     return true;
454 }
455 
Decode1001nnnn()456 bool ExidxEntryParser::Decode1001nnnn()
457 {
458     uint8_t bits = curOp_ & 0xf;
459     if (bits == REG_ARM_R13 || bits == REG_ARM_R15) {
460         DFXLOGU("10011101 or 10011111: Reserved");
461         lastErrorData_.SetCode(UNW_ERROR_RESERVED_VALUE);
462         return false;
463     }
464     // 1001nnnn: Set vsp = r[nnnn]
465     if ((bits == REG_ARM_R7) || (bits == REG_ARM_R11)) {
466         DFXLOGU("1001nnnn: Set vsp = R%{public}d", bits);
467         if (context_.transformedBits == 0) {
468             // No register transformed, ignore vsp offset.
469             context_.Reset();
470         }
471     } else {
472         INSTR_STATISTIC(UnsupportedArmExidx, bits, curOp_);
473         return false;
474     }
475     rsState_->cfaReg = bits;
476     rsState_->cfaRegOffset = 0;
477     return true;
478 }
479 
Decode1010nnnn()480 bool ExidxEntryParser::Decode1010nnnn()
481 {
482     // 10100nnn: Pop r4-r[4+nnn]
483     // 10101nnn: Pop r4-r[4+nnn], r14
484     size_t startReg = REG_ARM_R4;
485     size_t endReg = REG_ARM_R4 + (curOp_ & 0x7);
486     std::string msg = "Pop r" + std::to_string(startReg);
487     if (endReg > startReg) {
488         msg += "-r" + std::to_string(endReg);
489     }
490     if (curOp_ & 0x8) {
491         msg += ", r14";
492     }
493     DFXLOGU("%{public}s", msg.c_str());
494 
495     for (size_t reg = startReg; reg <= endReg; reg++) {
496         context_.Transform(reg);
497         context_.AddUpVsp(FOUR_BYTE_OFFSET);
498     }
499 
500     if (curOp_ & 0x8) {
501         context_.Transform(REG_LR);
502         context_.AddUpVsp(FOUR_BYTE_OFFSET);
503     }
504     return true;
505 }
506 
Decode10110000()507 inline bool ExidxEntryParser::Decode10110000()
508 {
509     DFXLOGU("10110000: Finish");
510     lastErrorData_.SetCode(UNW_ERROR_ARM_EXIDX_FINISH);
511     return true;
512 }
513 
Decode101100010000iiii()514 bool ExidxEntryParser::Decode101100010000iiii()
515 {
516     if (!GetOpCode()) {
517         return false;
518     }
519     // 10110001 00000000: spare
520     // 10110001 xxxxyyyy: spare (xxxx != 0000)
521     if (curOp_ == 0x00 || (curOp_ & 0xf0) != 0) {
522         return DecodeSpare();
523     }
524 
525     // 10110001 0000iiii(i not all 0) Pop integer registers under mask{r3, r2, r1, r0}
526     uint8_t registers = curOp_ & 0x0f;
527     DFXLOGU("10110001 0000iiii, registers: %{public}02x", registers);
528     for (size_t reg = 0; reg < 4; reg++) { // 4 : four registers {r3, r2, r1, r0}
529         if ((registers & (1 << reg))) {
530             context_.AddUpVsp(FOUR_BYTE_OFFSET);
531         }
532     }
533     return true;
534 }
535 
Decode10110010uleb128()536 bool ExidxEntryParser::Decode10110010uleb128()
537 {
538     // 10110010 uleb128 vsp = vsp + 0x204 + (uleb128 << 2)
539     uint8_t shift = 0;
540     uint32_t uleb128 = 0;
541     do {
542         if (!GetOpCode()) {
543             return false;
544         }
545         uleb128 |= (curOp_ & 0x7f) << shift;
546         shift += SEVEN_BIT_OFFSET;
547     } while ((curOp_ & 0x80) != 0);
548     uint32_t offset = 0x204 + (uleb128 << TWO_BIT_OFFSET);
549     DFXLOGU("vsp = vsp + %{public}d", offset);
550     context_.AddUpVsp(offset);
551     return true;
552 }
553 
Decode10110011sssscccc()554 inline bool ExidxEntryParser::Decode10110011sssscccc()
555 {
556     // Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX
557     if (!GetOpCode()) {
558         return false;
559     }
560     uint8_t popRegCount = (curOp_ & 0x0f) + 1;
561     uint32_t offset = popRegCount * 8 + 4;
562     context_.AddUpVsp(offset);
563     return true;
564 }
565 
Decode101101nn()566 inline bool ExidxEntryParser::Decode101101nn()
567 {
568     return DecodeSpare();
569 }
570 
Decode10111nnn()571 inline bool ExidxEntryParser::Decode10111nnn()
572 {
573     // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
574     uint8_t popRegCount = (curOp_ & 0x07) + 1;
575     uint32_t offset = popRegCount * 8 + 4;
576     context_.AddUpVsp(offset);
577     return true;
578 }
579 
Decode11000110sssscccc()580 inline bool ExidxEntryParser::Decode11000110sssscccc()
581 {
582     // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e)
583     if (!GetOpCode()) {
584         return false;
585     }
586     return Decode11000nnn();
587 }
588 
Decode110001110000iiii()589 bool ExidxEntryParser::Decode110001110000iiii()
590 {
591     // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}
592     if (!GetOpCode()) {
593         return false;
594     }
595     // 11000111 00000000: Spare
596     // 11000111 xxxxyyyy: Spare (xxxx != 0000)
597     if ((curOp_ & 0xf0) != 0 || curOp_ == 0) {
598         return DecodeSpare();
599     }
600 
601     // 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
602     for (size_t i = 0; i < 4; i++) { // 4 : four registers
603         if (curOp_ & (1 << i)) {
604             context_.AddUpVsp(FOUR_BYTE_OFFSET);
605         }
606     }
607     return true;
608 }
609 
Decode1100100nsssscccc()610 inline bool ExidxEntryParser::Decode1100100nsssscccc()
611 {
612     // 11001000 sssscccc: Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] by VPUSH
613     // 11001001 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by VPUSH
614     if (!GetOpCode()) {
615         return false;
616     }
617     uint8_t popRegCount = (curOp_ & 0x0f) + 1;
618     uint32_t offset = popRegCount * 8;
619     context_.AddUpVsp(offset);
620     return true;
621 }
622 
Decode11001yyy()623 inline bool ExidxEntryParser::Decode11001yyy()
624 {
625     // 11001yyy: Spare (yyy != 000, 001)
626     return DecodeSpare();
627 }
628 
Decode11000nnn()629 inline bool ExidxEntryParser::Decode11000nnn()
630 {
631     // Intel Wireless MMX pop wR[10]-wR[10+nnn]
632     uint8_t popRegCount = (curOp_ & 0x0f) + 1;
633     uint32_t offset = popRegCount * 8;
634     context_.AddUpVsp(offset);
635     return true;
636 }
637 
Decode11010nnn()638 inline bool ExidxEntryParser::Decode11010nnn()
639 {
640     // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by VPUSH (seeremark d)
641     uint8_t popRegCount = (curOp_ & 0x0f) + 1;
642     uint32_t offset = popRegCount * 8;
643     context_.AddUpVsp(offset);
644     return true;
645 }
646 
Decode11xxxyyy()647 inline bool ExidxEntryParser::Decode11xxxyyy()
648 {
649     // 11xxxyyy: Spare (xxx != 000, 001, 010)
650     return DecodeSpare();
651 }
652 } // namespace HiviewDFX
653 } // namespace OHOS
654 #endif