1 /*
2 * Copyright (c) 2023-2024 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 "arm_exidx.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 "DfxArmExidx"
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
ArmExidx(std::shared_ptr<DfxMemory> memory)91 ArmExidx::ArmExidx(std::shared_ptr<DfxMemory> memory) : memory_(memory)
92 {
93 (void)memset_s(&lastErrorData_, sizeof(UnwindErrorData), 0, sizeof(UnwindErrorData));
94 context_.Reset(DfxRegsQut::GetQutRegsSize());
95 }
96
FlushInstr()97 inline void ArmExidx::FlushInstr()
98 {
99 if (rsState_->cfaReg == 0) {
100 rsState_->cfaReg = REG_SP;
101 }
102 rsState_->cfaRegOffset = 0;
103 if (context_.vsp != 0) {
104 if (__builtin_expect(!((context_.vsp & 0x3) == 0), false)) {
105 DFXLOGE("Check failed: context_.vsp & 0x3) == 0");
106 }
107 rsState_->cfaRegOffset = context_.vsp;
108 }
109 DFXLOGU("rsState cfaReg: %{public}d, cfaRegOffset: %{public}d", rsState_->cfaReg, rsState_->cfaRegOffset);
110
111 auto qutRegs = DfxRegsQut::GetQutRegs();
112 for (size_t i = 0; i < qutRegs.size(); i++) {
113 uint32_t reg = static_cast<uint32_t>(qutRegs[i]);
114 if (context_.IsTransformed(reg)) {
115 if (__builtin_expect(!((context_.regs[i] & 0x3) == 0), false)) {
116 DFXLOGE("Check failed: context_.regs[%{public}zu] & 0x3) == 0", i);
117 }
118 rsState_->locs[i].type = REG_LOC_MEM_OFFSET;
119 rsState_->locs[i].val = -context_.regs[i];
120 DFXLOGU("rsState reg: %{public}d, locs[%{public}d].val: %{public}d", reg, i, rsState_->locs[i].val);
121 }
122 }
123
124 if (!isPcSet_) {
125 rsState_->returnAddressRegister = REG_LR;
126 } else {
127 rsState_->returnAddressRegister = REG_PC;
128 }
129
130 context_.Reset();
131 }
132
LogRawData()133 inline void ArmExidx::LogRawData()
134 {
135 std::string logStr("Raw Data:");
136 for (const uint8_t data : ops_) {
137 logStr += StringPrintf(" 0x%02x", data);
138 }
139 DFXLOGU("%{public}s", logStr.c_str());
140 }
141
SearchEntry(uintptr_t pc,struct UnwindTableInfo uti,struct UnwindEntryInfo & uei)142 bool ArmExidx::SearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei)
143 {
144 uintptr_t tableLen = uti.tableLen / ARM_EXIDX_TABLE_SIZE;
145 uintptr_t tableData = uti.tableData;
146 DFXLOGU("SearchEntry pc: %{public}p tableData: %{public}p, tableLen: %{public}u",
147 (void*)pc, (void*)tableData, (uint32_t)tableLen);
148 if (tableLen == 0) {
149 lastErrorData_.SetCode(UNW_ERROR_NO_UNWIND_INFO);
150 return false;
151 }
152
153 // do binary search
154 uintptr_t entry = 0;
155 uintptr_t low = 0;
156 uintptr_t high = tableLen;
157 while (low < high) {
158 uintptr_t cur = (low + high) / 2; // 2 : binary search divided parameter
159 uintptr_t ptr = tableData + cur * ARM_EXIDX_TABLE_SIZE;
160 uintptr_t addr = 0;
161 if (!memory_->ReadPrel31(ptr, &addr)) {
162 lastErrorData_.SetAddrAndCode(ptr, UNW_ERROR_ILLEGAL_VALUE);
163 return false;
164 }
165
166 if (pc == addr) {
167 entry = ptr;
168 break;
169 }
170 if (pc < addr) {
171 high = cur;
172 } else {
173 low = cur + 1;
174 }
175 }
176 if (entry == 0) {
177 if (high != 0) {
178 entry = tableData + (high - 1) * ARM_EXIDX_TABLE_SIZE;
179 } else {
180 lastErrorData_.SetCode(UNW_ERROR_NO_UNWIND_INFO);
181 return false;
182 }
183 }
184
185 uei.unwindInfoSize = ARM_EXIDX_TABLE_SIZE;
186 uei.unwindInfo = (void *) entry;
187 uei.format = UNW_INFO_FORMAT_ARM_EXIDX;
188 return true;
189 }
190
ExtractEntryData(uintptr_t entryOffset)191 bool ArmExidx::ExtractEntryData(uintptr_t entryOffset)
192 {
193 DFXLOGU("Exidx entryOffset: %{public}llx", (uint64_t)entryOffset);
194 ops_.clear();
195 uint32_t data = 0;
196 if (entryOffset & 1) {
197 DFXLOGE("[%{public}d]: entryOffset: %{public}llx error.", __LINE__, (uint64_t)entryOffset);
198 lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_INVALID_ALIGNMENT);
199 return false;
200 }
201
202 entryOffset += FOUR_BYTE_OFFSET;
203 if (!memory_->Read<uint32_t>(entryOffset, &data, false)) {
204 DFXLOGE("[%{public}d]: entryOffset: %{public}llx error.", __LINE__, (uint64_t)entryOffset);
205 lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_ILLEGAL_VALUE);
206 return false;
207 }
208
209 if (data == ARM_EXIDX_CANT_UNWIND) {
210 DFXLOGU("This is a CANT UNWIND entry, data: %{public}x.", data);
211 lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_CANT_UNWIND);
212 return false;
213 } else if ((data & ARM_EXIDX_COMPACT) != 0) {
214 if (((data >> TWENTY_FOUR_BIT_OFFSET) & 0x7f) != 0) {
215 DFXLOGE("This is a non-zero index, this code doesn't support other formats.");
216 lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
217 return false;
218 }
219 DFXLOGU("This is a compact table entry, data: %{public}x.", data);
220 ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
221 ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
222 uint8_t lastOp = data & 0xff;
223 ops_.push_back(lastOp);
224 if (lastOp != ARM_EXTBL_OP_FINISH) {
225 ops_.push_back(ARM_EXTBL_OP_FINISH);
226 }
227 LogRawData();
228 return true;
229 }
230
231 uintptr_t extabAddr = 0;
232 // prel31 decode point to .ARM.extab
233 #ifndef TEST_ARM_EXIDX
234 if (!memory_->ReadPrel31(entryOffset, &extabAddr)) {
235 lastErrorData_.SetAddrAndCode(entryOffset, UNW_ERROR_INVALID_MEMORY);
236 return false;
237 }
238 #else
239 extabAddr = entryOffset + FOUR_BYTE_OFFSET;
240 #endif
241 return ExtractEntryTab(extabAddr);
242 }
243
ExtractEntryTabByPersonality(uintptr_t & tabOffset,uint32_t & data,uint8_t & tableCount)244 bool ArmExidx::ExtractEntryTabByPersonality(uintptr_t& tabOffset, uint32_t& data, uint8_t& tableCount)
245 {
246 if ((data & ARM_EXIDX_COMPACT) == 0) {
247 DFXLOGU("Arm generic personality, data: %{public}x.", data);
248 #ifndef TEST_ARM_EXIDX
249 uintptr_t perRoutine;
250 if (!memory_->ReadPrel31(tabOffset, &perRoutine)) {
251 DFXLOGE("Arm Personality routine error");
252 lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
253 return false;
254 }
255 #endif
256
257 tabOffset += FOUR_BYTE_OFFSET;
258 // Skip four bytes, because dont have unwind data to read
259 if (!memory_->Read<uint32_t>(tabOffset, &data, false)) {
260 lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
261 return false;
262 }
263 tableCount = (data >> TWENTY_FOUR_BIT_OFFSET) & 0xff;
264 ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
265 ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
266 ops_.push_back(data & 0xff);
267 tabOffset += FOUR_BYTE_OFFSET;
268 } else {
269 DFXLOGU("Arm compact personality, data: %{public}x.", data);
270 if ((data >> TWENTY_EIGHT_BIT_OFFSET) != 0x8) {
271 DFXLOGE("incorrect Arm compact model, [31:28]bit must be 0x8(%{public}x)",
272 data >> TWENTY_EIGHT_BIT_OFFSET);
273 lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
274 return false;
275 }
276 uint8_t personality = (data >> TWENTY_FOUR_BIT_OFFSET) & 0x3;
277 if (personality > 2) { // 2 : personality must be 0 1 2
278 DFXLOGE("incorrect Arm compact personality(%{public}u)", personality);
279 lastErrorData_.SetCode(UNW_ERROR_INVALID_PERSONALITY);
280 return false;
281 }
282 // inline compact model, when personality is 0
283 if (personality == 0) {
284 ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
285 } else if (personality == 1 || personality == 2) { // 2 : personality equal to 2
286 tableCount = (data >> SIXTEEN_BIT_OFFSET) & 0xff;
287 tabOffset += FOUR_BYTE_OFFSET;
288 }
289 ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
290 ops_.push_back(data & 0xff);
291 }
292 return true;
293 }
294
ExtractEntryTab(uintptr_t tabOffset)295 bool ArmExidx::ExtractEntryTab(uintptr_t tabOffset)
296 {
297 uint32_t data = 0;
298 DFXLOGU("Exidx tabOffset: %{public}llx", static_cast<uint64_t>(tabOffset));
299 if (!memory_->Read<uint32_t>(tabOffset, &data, false)) {
300 lastErrorData_.SetAddrAndCode(tabOffset, UNW_ERROR_INVALID_MEMORY);
301 return false;
302 }
303
304 uint8_t tableCount = 0;
305 if (!ExtractEntryTabByPersonality(tabOffset, data, tableCount)) {
306 return false;
307 }
308
309 if (tableCount > 5) { // 5 : 5 operators
310 lastErrorData_.SetCode(UNW_ERROR_NOT_SUPPORT);
311 return false;
312 }
313
314 for (size_t i = 0; i < tableCount; i++) {
315 if (!memory_->Read<uint32_t>(tabOffset, &data, false)) {
316 return false;
317 }
318 tabOffset += FOUR_BYTE_OFFSET;
319 ops_.push_back((data >> TWENTY_FOUR_BIT_OFFSET) & 0xff);
320 ops_.push_back((data >> SIXTEEN_BIT_OFFSET) & 0xff);
321 ops_.push_back((data >> EIGHT_BIT_OFFSET) & 0xff);
322 ops_.push_back(data & 0xff);
323 }
324
325 if (!ops_.empty() && ops_.back() != ARM_EXTBL_OP_FINISH) {
326 ops_.push_back(ARM_EXTBL_OP_FINISH);
327 }
328 LogRawData();
329 return true;
330 }
331
GetOpCode()332 inline bool ArmExidx::GetOpCode()
333 {
334 if (ops_.empty()) {
335 return false;
336 }
337 curOp_ = ops_.front();
338 ops_.pop_front();
339 DFXLOGU("curOp: %{public}llx", (uint64_t)curOp_);
340 return true;
341 }
342
Eval(uintptr_t entryOffset)343 bool ArmExidx::Eval(uintptr_t entryOffset)
344 {
345 if (!ExtractEntryData(entryOffset)) {
346 return false;
347 }
348
349 DecodeTable decodeTable[] = {
350 {0xc0, 0x00, &ArmExidx::Decode00xxxxxx},
351 {0xc0, 0x40, &ArmExidx::Decode01xxxxxx},
352 {0xf0, 0x80, &ArmExidx::Decode1000iiiiiiiiiiii},
353 {0xf0, 0x90, &ArmExidx::Decode1001nnnn},
354 {0xf0, 0xa0, &ArmExidx::Decode1010nnnn},
355 {0xff, 0xb0, &ArmExidx::Decode10110000},
356 {0xff, 0xb1, &ArmExidx::Decode101100010000iiii},
357 {0xff, 0xb2, &ArmExidx::Decode10110010uleb128},
358 {0xff, 0xb3, &ArmExidx::Decode10110011sssscccc},
359 {0xfc, 0xb4, &ArmExidx::Decode101101nn},
360 {0xf8, 0xb8, &ArmExidx::Decode10111nnn},
361 {0xff, 0xc6, &ArmExidx::Decode11000110sssscccc},
362 {0xff, 0xc7, &ArmExidx::Decode110001110000iiii},
363 {0xfe, 0xc8, &ArmExidx::Decode1100100nsssscccc},
364 {0xc8, 0xc8, &ArmExidx::Decode11001yyy},
365 {0xf8, 0xc0, &ArmExidx::Decode11000nnn},
366 {0xf8, 0xd0, &ArmExidx::Decode11010nnn},
367 {0xc0, 0xc0, &ArmExidx::Decode11xxxyyy}
368 };
369 context_.Reset();
370 while (Decode(decodeTable, sizeof(decodeTable) / sizeof(decodeTable[0])));
371 return true;
372 }
373
Step(uintptr_t entryOffset,std::shared_ptr<RegLocState> rs)374 bool ArmExidx::Step(uintptr_t entryOffset, std::shared_ptr<RegLocState> rs)
375 {
376 if (rs == nullptr) {
377 return false;
378 }
379 rsState_ = rs;
380
381 if (!Eval(entryOffset)) {
382 return false;
383 }
384
385 FlushInstr();
386 return true;
387 }
388
DecodeSpare()389 inline bool ArmExidx::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 inline bool ArmExidx::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 ArmExidx::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 ArmExidx::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 inline bool ArmExidx::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 inline bool ArmExidx::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 inline bool ArmExidx::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 ArmExidx::Decode10110000()
508 {
509 DFXLOGU("10110000: Finish");
510 lastErrorData_.SetCode(UNW_ERROR_ARM_EXIDX_FINISH);
511 return true;
512 }
513
Decode101100010000iiii()514 inline bool ArmExidx::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 inline bool ArmExidx::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 ArmExidx::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 ArmExidx::Decode101101nn()
567 {
568 return DecodeSpare();
569 }
570
Decode10111nnn()571 inline bool ArmExidx::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 ArmExidx::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 inline bool ArmExidx::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 ArmExidx::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 ArmExidx::Decode11001yyy()
624 {
625 // 11001yyy: Spare (yyy != 000, 001)
626 return DecodeSpare();
627 }
628
Decode11000nnn()629 inline bool ArmExidx::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 ArmExidx::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 ArmExidx::Decode11xxxyyy()
648 {
649 // 11xxxyyy: Spare (xxx != 000, 001, 010)
650 return DecodeSpare();
651 }
652 } // namespace HiviewDFX
653 } // namespace OHOS
654 #endif