1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
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
17 #include <inttypes.h>
18 #include <stdint.h>
19
20 #include <deque>
21 #include <string>
22
23 #include <android-base/stringprintf.h>
24
25 #include <unwindstack/Log.h>
26 #include <unwindstack/MachineArm.h>
27 #include <unwindstack/Memory.h>
28 #include <unwindstack/RegsArm.h>
29
30 #include "ArmExidx.h"
31 #include "Check.h"
32
33 namespace unwindstack {
34
35 static constexpr uint8_t LOG_CFA_REG = 64;
36
LogRawData()37 void ArmExidx::LogRawData() {
38 std::string log_str("Raw Data:");
39 for (const uint8_t data : data_) {
40 log_str += android::base::StringPrintf(" 0x%02x", data);
41 }
42 Log::Info(log_indent_, "%s", log_str.c_str());
43 }
44
ExtractEntryData(uint32_t entry_offset)45 bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
46 data_.clear();
47 status_ = ARM_STATUS_NONE;
48
49 if (entry_offset & 1) {
50 // The offset needs to be at least two byte aligned.
51 status_ = ARM_STATUS_INVALID_ALIGNMENT;
52 return false;
53 }
54
55 // Each entry is a 32 bit prel31 offset followed by 32 bits
56 // of unwind information. If bit 31 of the unwind data is zero,
57 // then this is a prel31 offset to the start of the unwind data.
58 // If the unwind data is 1, then this is a cant unwind entry.
59 // Otherwise, this data is the compact form of the unwind information.
60 uint32_t data;
61 if (!elf_memory_->Read32(entry_offset + 4, &data)) {
62 status_ = ARM_STATUS_READ_FAILED;
63 status_address_ = entry_offset + 4;
64 return false;
65 }
66 if (data == 1) {
67 // This is a CANT UNWIND entry.
68 status_ = ARM_STATUS_NO_UNWIND;
69 if (log_type_ != ARM_LOG_NONE) {
70 if (log_type_ == ARM_LOG_FULL) {
71 Log::Info(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
72 }
73 Log::Info(log_indent_, "[cantunwind]");
74 }
75 return false;
76 }
77
78 if (data & (1UL << 31)) {
79 // This is a compact table entry.
80 if ((data >> 24) & 0xf) {
81 // This is a non-zero index, this code doesn't support
82 // other formats.
83 status_ = ARM_STATUS_INVALID_PERSONALITY;
84 return false;
85 }
86 data_.push_back((data >> 16) & 0xff);
87 data_.push_back((data >> 8) & 0xff);
88 uint8_t last_op = data & 0xff;
89 data_.push_back(last_op);
90 if (last_op != ARM_OP_FINISH) {
91 // If this didn't end with a finish op, add one.
92 data_.push_back(ARM_OP_FINISH);
93 }
94 if (log_type_ == ARM_LOG_FULL) {
95 LogRawData();
96 }
97 return true;
98 }
99
100 // Get the address of the ops.
101 // Sign extend the data value if necessary.
102 int32_t signed_data = static_cast<int32_t>(data << 1) >> 1;
103 uint32_t addr = (entry_offset + 4) + signed_data;
104 if (!elf_memory_->Read32(addr, &data)) {
105 status_ = ARM_STATUS_READ_FAILED;
106 status_address_ = addr;
107 return false;
108 }
109
110 size_t num_table_words;
111 if (data & (1UL << 31)) {
112 // Compact model.
113 switch ((data >> 24) & 0xf) {
114 case 0:
115 num_table_words = 0;
116 data_.push_back((data >> 16) & 0xff);
117 break;
118 case 1:
119 case 2:
120 num_table_words = (data >> 16) & 0xff;
121 addr += 4;
122 break;
123 default:
124 // Only a personality of 0, 1, 2 is valid.
125 status_ = ARM_STATUS_INVALID_PERSONALITY;
126 return false;
127 }
128 data_.push_back((data >> 8) & 0xff);
129 data_.push_back(data & 0xff);
130 } else {
131 // Generic model.
132
133 // Skip the personality routine data, it doesn't contain any data
134 // needed to decode the unwind information.
135 addr += 4;
136 if (!elf_memory_->Read32(addr, &data)) {
137 status_ = ARM_STATUS_READ_FAILED;
138 status_address_ = addr;
139 return false;
140 }
141 num_table_words = (data >> 24) & 0xff;
142 data_.push_back((data >> 16) & 0xff);
143 data_.push_back((data >> 8) & 0xff);
144 data_.push_back(data & 0xff);
145 addr += 4;
146 }
147
148 if (num_table_words > 5) {
149 status_ = ARM_STATUS_MALFORMED;
150 return false;
151 }
152
153 for (size_t i = 0; i < num_table_words; i++) {
154 if (!elf_memory_->Read32(addr, &data)) {
155 status_ = ARM_STATUS_READ_FAILED;
156 status_address_ = addr;
157 return false;
158 }
159 data_.push_back((data >> 24) & 0xff);
160 data_.push_back((data >> 16) & 0xff);
161 data_.push_back((data >> 8) & 0xff);
162 data_.push_back(data & 0xff);
163 addr += 4;
164 }
165
166 if (data_.back() != ARM_OP_FINISH) {
167 // If this didn't end with a finish op, add one.
168 data_.push_back(ARM_OP_FINISH);
169 }
170
171 if (log_type_ == ARM_LOG_FULL) {
172 LogRawData();
173 }
174 return true;
175 }
176
GetByte(uint8_t * byte)177 inline bool ArmExidx::GetByte(uint8_t* byte) {
178 if (data_.empty()) {
179 status_ = ARM_STATUS_TRUNCATED;
180 return false;
181 }
182 *byte = data_.front();
183 data_.pop_front();
184 return true;
185 }
186
DecodePrefix_10_00(uint8_t byte)187 inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
188 CHECK((byte >> 4) == 0x8);
189
190 uint16_t registers = (byte & 0xf) << 8;
191 if (!GetByte(&byte)) {
192 return false;
193 }
194
195 registers |= byte;
196 if (registers == 0) {
197 // 10000000 00000000: Refuse to unwind
198 if (log_type_ != ARM_LOG_NONE) {
199 Log::Info(log_indent_, "Refuse to unwind");
200 }
201 status_ = ARM_STATUS_NO_UNWIND;
202 return false;
203 }
204 // 1000iiii iiiiiiii: Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
205 registers <<= 4;
206
207 if (log_type_ != ARM_LOG_NONE) {
208 if (log_type_ == ARM_LOG_FULL) {
209 bool add_comma = false;
210 std::string msg = "pop {";
211 for (size_t reg = 4; reg < 16; reg++) {
212 if (registers & (1 << reg)) {
213 if (add_comma) {
214 msg += ", ";
215 }
216 msg += android::base::StringPrintf("r%zu", reg);
217 add_comma = true;
218 }
219 }
220 Log::Info(log_indent_, "%s}", msg.c_str());
221 } else {
222 uint32_t cfa_offset = __builtin_popcount(registers) * 4;
223 log_cfa_offset_ += cfa_offset;
224 for (size_t reg = 4; reg < 16; reg++) {
225 if (registers & (1 << reg)) {
226 log_regs_[reg] = cfa_offset;
227 cfa_offset -= 4;
228 }
229 }
230 }
231
232 if (log_skip_execution_) {
233 return true;
234 }
235 }
236
237 for (size_t reg = 4; reg < 16; reg++) {
238 if (registers & (1 << reg)) {
239 if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
240 status_ = ARM_STATUS_READ_FAILED;
241 status_address_ = cfa_;
242 return false;
243 }
244 cfa_ += 4;
245 }
246 }
247
248 // If the sp register is modified, change the cfa value.
249 if (registers & (1 << ARM_REG_SP)) {
250 cfa_ = (*regs_)[ARM_REG_SP];
251 }
252
253 // Indicate if the pc register was set.
254 if (registers & (1 << ARM_REG_PC)) {
255 pc_set_ = true;
256 }
257 return true;
258 }
259
DecodePrefix_10_01(uint8_t byte)260 inline bool ArmExidx::DecodePrefix_10_01(uint8_t byte) {
261 CHECK((byte >> 4) == 0x9);
262
263 uint8_t bits = byte & 0xf;
264 if (bits == 13 || bits == 15) {
265 // 10011101: Reserved as prefix for ARM register to register moves
266 // 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
267 if (log_type_ != ARM_LOG_NONE) {
268 Log::Info(log_indent_, "[Reserved]");
269 }
270 status_ = ARM_STATUS_RESERVED;
271 return false;
272 }
273 // 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
274 if (log_type_ != ARM_LOG_NONE) {
275 if (log_type_ == ARM_LOG_FULL) {
276 Log::Info(log_indent_, "vsp = r%d", bits);
277 } else {
278 log_regs_[LOG_CFA_REG] = bits;
279 }
280
281 if (log_skip_execution_) {
282 return true;
283 }
284 }
285 // It is impossible for bits to be larger than the total number of
286 // arm registers, so don't bother checking if bits is a valid register.
287 cfa_ = (*regs_)[bits];
288 return true;
289 }
290
DecodePrefix_10_10(uint8_t byte)291 inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
292 CHECK((byte >> 4) == 0xa);
293
294 // 10100nnn: Pop r4-r[4+nnn]
295 // 10101nnn: Pop r4-r[4+nnn], r14
296 if (log_type_ != ARM_LOG_NONE) {
297 uint8_t end_reg = byte & 0x7;
298 if (log_type_ == ARM_LOG_FULL) {
299 std::string msg = "pop {r4";
300 if (end_reg) {
301 msg += android::base::StringPrintf("-r%d", 4 + end_reg);
302 }
303 if (byte & 0x8) {
304 Log::Info(log_indent_, "%s, r14}", msg.c_str());
305 } else {
306 Log::Info(log_indent_, "%s}", msg.c_str());
307 }
308 } else {
309 end_reg += 4;
310 uint32_t cfa_offset = (end_reg - 3) * 4;
311 if (byte & 0x8) {
312 cfa_offset += 4;
313 }
314 log_cfa_offset_ += cfa_offset;
315
316 for (uint8_t reg = 4; reg <= end_reg; reg++) {
317 log_regs_[reg] = cfa_offset;
318 cfa_offset -= 4;
319 }
320
321 if (byte & 0x8) {
322 log_regs_[14] = cfa_offset;
323 }
324 }
325
326 if (log_skip_execution_) {
327 return true;
328 }
329 }
330
331 for (size_t i = 4; i <= 4 + (byte & 0x7); i++) {
332 if (!process_memory_->Read32(cfa_, &(*regs_)[i])) {
333 status_ = ARM_STATUS_READ_FAILED;
334 status_address_ = cfa_;
335 return false;
336 }
337 cfa_ += 4;
338 }
339 if (byte & 0x8) {
340 if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) {
341 status_ = ARM_STATUS_READ_FAILED;
342 status_address_ = cfa_;
343 return false;
344 }
345 cfa_ += 4;
346 }
347 return true;
348 }
349
DecodePrefix_10_11_0000()350 inline bool ArmExidx::DecodePrefix_10_11_0000() {
351 // 10110000: Finish
352 if (log_type_ != ARM_LOG_NONE) {
353 if (log_type_ == ARM_LOG_FULL) {
354 Log::Info(log_indent_, "finish");
355 }
356
357 if (log_skip_execution_) {
358 status_ = ARM_STATUS_FINISH;
359 return false;
360 }
361 }
362 status_ = ARM_STATUS_FINISH;
363 return false;
364 }
365
DecodePrefix_10_11_0001()366 inline bool ArmExidx::DecodePrefix_10_11_0001() {
367 uint8_t byte;
368 if (!GetByte(&byte)) {
369 return false;
370 }
371
372 if (byte == 0) {
373 // 10110001 00000000: Spare
374 if (log_type_ != ARM_LOG_NONE) {
375 Log::Info(log_indent_, "Spare");
376 }
377 status_ = ARM_STATUS_SPARE;
378 return false;
379 }
380 if (byte >> 4) {
381 // 10110001 xxxxyyyy: Spare (xxxx != 0000)
382 if (log_type_ != ARM_LOG_NONE) {
383 Log::Info(log_indent_, "Spare");
384 }
385 status_ = ARM_STATUS_SPARE;
386 return false;
387 }
388
389 // 10110001 0000iiii: Pop integer registers under mask {r3, r2, r1, r0}
390 if (log_type_ != ARM_LOG_NONE) {
391 if (log_type_ == ARM_LOG_FULL) {
392 bool add_comma = false;
393 std::string msg = "pop {";
394 for (size_t i = 0; i < 4; i++) {
395 if (byte & (1 << i)) {
396 if (add_comma) {
397 msg += ", ";
398 }
399 msg += android::base::StringPrintf("r%zu", i);
400 add_comma = true;
401 }
402 }
403 Log::Info(log_indent_, "%s}", msg.c_str());
404 } else {
405 byte &= 0xf;
406 uint32_t cfa_offset = __builtin_popcount(byte) * 4;
407 log_cfa_offset_ += cfa_offset;
408 for (size_t reg = 0; reg < 4; reg++) {
409 if (byte & (1 << reg)) {
410 log_regs_[reg] = cfa_offset;
411 cfa_offset -= 4;
412 }
413 }
414 }
415
416 if (log_skip_execution_) {
417 return true;
418 }
419 }
420
421 for (size_t reg = 0; reg < 4; reg++) {
422 if (byte & (1 << reg)) {
423 if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
424 status_ = ARM_STATUS_READ_FAILED;
425 status_address_ = cfa_;
426 return false;
427 }
428 cfa_ += 4;
429 }
430 }
431 return true;
432 }
433
AdjustRegisters(int32_t offset)434 inline void ArmExidx::AdjustRegisters(int32_t offset) {
435 for (auto& entry : log_regs_) {
436 if (entry.first >= LOG_CFA_REG) {
437 break;
438 }
439 entry.second += offset;
440 }
441 }
442
DecodePrefix_10_11_0010()443 inline bool ArmExidx::DecodePrefix_10_11_0010() {
444 // 10110010 uleb128: vsp = vsp + 0x204 + (uleb128 << 2)
445 uint32_t result = 0;
446 uint32_t shift = 0;
447 uint8_t byte;
448 do {
449 if (!GetByte(&byte)) {
450 return false;
451 }
452
453 result |= (byte & 0x7f) << shift;
454 shift += 7;
455 } while (byte & 0x80);
456 result <<= 2;
457 if (log_type_ != ARM_LOG_NONE) {
458 int32_t cfa_offset = 0x204 + result;
459 if (log_type_ == ARM_LOG_FULL) {
460 Log::Info(log_indent_, "vsp = vsp + %d", cfa_offset);
461 } else {
462 log_cfa_offset_ += cfa_offset;
463 }
464 AdjustRegisters(cfa_offset);
465
466 if (log_skip_execution_) {
467 return true;
468 }
469 }
470 cfa_ += 0x204 + result;
471 return true;
472 }
473
DecodePrefix_10_11_0011()474 inline bool ArmExidx::DecodePrefix_10_11_0011() {
475 // 10110011 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX
476 uint8_t byte;
477 if (!GetByte(&byte)) {
478 return false;
479 }
480
481 if (log_type_ != ARM_LOG_NONE) {
482 uint8_t start_reg = byte >> 4;
483 uint8_t end_reg = start_reg + (byte & 0xf);
484
485 if (log_type_ == ARM_LOG_FULL) {
486 std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
487 if (end_reg) {
488 msg += android::base::StringPrintf("-d%d", end_reg);
489 }
490 Log::Info(log_indent_, "%s}", msg.c_str());
491 } else {
492 Log::Info(log_indent_, "Unsupported DX register display");
493 }
494
495 if (log_skip_execution_) {
496 return true;
497 }
498 }
499 cfa_ += (byte & 0xf) * 8 + 12;
500 return true;
501 }
502
DecodePrefix_10_11_01nn()503 inline bool ArmExidx::DecodePrefix_10_11_01nn() {
504 // 101101nn: Spare
505 if (log_type_ != ARM_LOG_NONE) {
506 Log::Info(log_indent_, "Spare");
507 }
508 status_ = ARM_STATUS_SPARE;
509 return false;
510 }
511
DecodePrefix_10_11_1nnn(uint8_t byte)512 inline bool ArmExidx::DecodePrefix_10_11_1nnn(uint8_t byte) {
513 CHECK((byte & ~0x07) == 0xb8);
514
515 // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
516 if (log_type_ != ARM_LOG_NONE) {
517 if (log_type_ == ARM_LOG_FULL) {
518 uint8_t last_reg = (byte & 0x7);
519 std::string msg = "pop {d8";
520 if (last_reg) {
521 msg += android::base::StringPrintf("-d%d", last_reg + 8);
522 }
523 Log::Info(log_indent_, "%s}", msg.c_str());
524 } else {
525 Log::Info(log_indent_, "Unsupported DX register display");
526 }
527
528 if (log_skip_execution_) {
529 return true;
530 }
531 }
532 // Only update the cfa.
533 cfa_ += (byte & 0x7) * 8 + 12;
534 return true;
535 }
536
DecodePrefix_10(uint8_t byte)537 inline bool ArmExidx::DecodePrefix_10(uint8_t byte) {
538 CHECK((byte >> 6) == 0x2);
539
540 switch ((byte >> 4) & 0x3) {
541 case 0:
542 return DecodePrefix_10_00(byte);
543 case 1:
544 return DecodePrefix_10_01(byte);
545 case 2:
546 return DecodePrefix_10_10(byte);
547 default:
548 switch (byte & 0xf) {
549 case 0:
550 return DecodePrefix_10_11_0000();
551 case 1:
552 return DecodePrefix_10_11_0001();
553 case 2:
554 return DecodePrefix_10_11_0010();
555 case 3:
556 return DecodePrefix_10_11_0011();
557 default:
558 if (byte & 0x8) {
559 return DecodePrefix_10_11_1nnn(byte);
560 } else {
561 return DecodePrefix_10_11_01nn();
562 }
563 }
564 }
565 }
566
DecodePrefix_11_000(uint8_t byte)567 inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
568 CHECK((byte & ~0x07) == 0xc0);
569
570 uint8_t bits = byte & 0x7;
571 if (bits == 6) {
572 if (!GetByte(&byte)) {
573 return false;
574 }
575
576 // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]
577 if (log_type_ != ARM_LOG_NONE) {
578 if (log_type_ == ARM_LOG_FULL) {
579 uint8_t start_reg = byte >> 4;
580 std::string msg = android::base::StringPrintf("pop {wR%d", start_reg);
581 uint8_t end_reg = byte & 0xf;
582 if (end_reg) {
583 msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
584 }
585 Log::Info(log_indent_, "%s}", msg.c_str());
586 } else {
587 Log::Info(log_indent_, "Unsupported wRX register display");
588 }
589
590 if (log_skip_execution_) {
591 return true;
592 }
593 }
594 // Only update the cfa.
595 cfa_ += (byte & 0xf) * 8 + 8;
596 } else if (bits == 7) {
597 if (!GetByte(&byte)) {
598 return false;
599 }
600
601 if (byte == 0) {
602 // 11000111 00000000: Spare
603 if (log_type_ != ARM_LOG_NONE) {
604 Log::Info(log_indent_, "Spare");
605 }
606 status_ = ARM_STATUS_SPARE;
607 return false;
608 } else if ((byte >> 4) == 0) {
609 // 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
610 if (log_type_ != ARM_LOG_NONE) {
611 if (log_type_ == ARM_LOG_FULL) {
612 bool add_comma = false;
613 std::string msg = "pop {";
614 for (size_t i = 0; i < 4; i++) {
615 if (byte & (1 << i)) {
616 if (add_comma) {
617 msg += ", ";
618 }
619 msg += android::base::StringPrintf("wCGR%zu", i);
620 add_comma = true;
621 }
622 }
623 Log::Info(log_indent_, "%s}", msg.c_str());
624 } else {
625 Log::Info(log_indent_, "Unsupported wCGR register display");
626 }
627
628 if (log_skip_execution_) {
629 return true;
630 }
631 }
632 // Only update the cfa.
633 cfa_ += __builtin_popcount(byte) * 4;
634 } else {
635 // 11000111 xxxxyyyy: Spare (xxxx != 0000)
636 if (log_type_ != ARM_LOG_NONE) {
637 Log::Info(log_indent_, "Spare");
638 }
639 status_ = ARM_STATUS_SPARE;
640 return false;
641 }
642 } else {
643 // 11000nnn: Intel Wireless MMX pop wR[10]-wR[10+nnn] (nnn != 6, 7)
644 if (log_type_ != ARM_LOG_NONE) {
645 if (log_type_ == ARM_LOG_FULL) {
646 std::string msg = "pop {wR10";
647 uint8_t nnn = byte & 0x7;
648 if (nnn) {
649 msg += android::base::StringPrintf("-wR%d", 10 + nnn);
650 }
651 Log::Info(log_indent_, "%s}", msg.c_str());
652 } else {
653 Log::Info(log_indent_, "Unsupported wRX register display");
654 }
655
656 if (log_skip_execution_) {
657 return true;
658 }
659 }
660 // Only update the cfa.
661 cfa_ += (byte & 0x7) * 8 + 8;
662 }
663 return true;
664 }
665
DecodePrefix_11_001(uint8_t byte)666 inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
667 CHECK((byte & ~0x07) == 0xc8);
668
669 uint8_t bits = byte & 0x7;
670 if (bits == 0) {
671 // 11001000 sssscccc: Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] by VPUSH
672 if (!GetByte(&byte)) {
673 return false;
674 }
675
676 if (log_type_ != ARM_LOG_NONE) {
677 if (log_type_ == ARM_LOG_FULL) {
678 uint8_t start_reg = byte >> 4;
679 std::string msg = android::base::StringPrintf("pop {d%d", 16 + start_reg);
680 uint8_t end_reg = byte & 0xf;
681 if (end_reg) {
682 msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
683 }
684 Log::Info(log_indent_, "%s}", msg.c_str());
685 } else {
686 Log::Info(log_indent_, "Unsupported DX register display");
687 }
688
689 if (log_skip_execution_) {
690 return true;
691 }
692 }
693 // Only update the cfa.
694 cfa_ += (byte & 0xf) * 8 + 8;
695 } else if (bits == 1) {
696 // 11001001 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by VPUSH
697 if (!GetByte(&byte)) {
698 return false;
699 }
700
701 if (log_type_ != ARM_LOG_NONE) {
702 if (log_type_ == ARM_LOG_FULL) {
703 uint8_t start_reg = byte >> 4;
704 std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
705 uint8_t end_reg = byte & 0xf;
706 if (end_reg) {
707 msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
708 }
709 Log::Info(log_indent_, "%s}", msg.c_str());
710 } else {
711 Log::Info(log_indent_, "Unsupported DX register display");
712 }
713
714 if (log_skip_execution_) {
715 return true;
716 }
717 }
718 // Only update the cfa.
719 cfa_ += (byte & 0xf) * 8 + 8;
720 } else {
721 // 11001yyy: Spare (yyy != 000, 001)
722 if (log_type_ != ARM_LOG_NONE) {
723 Log::Info(log_indent_, "Spare");
724 }
725 status_ = ARM_STATUS_SPARE;
726 return false;
727 }
728 return true;
729 }
730
DecodePrefix_11_010(uint8_t byte)731 inline bool ArmExidx::DecodePrefix_11_010(uint8_t byte) {
732 CHECK((byte & ~0x07) == 0xd0);
733
734 // 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
735 if (log_type_ != ARM_LOG_NONE) {
736 if (log_type_ == ARM_LOG_FULL) {
737 std::string msg = "pop {d8";
738 uint8_t end_reg = byte & 0x7;
739 if (end_reg) {
740 msg += android::base::StringPrintf("-d%d", 8 + end_reg);
741 }
742 Log::Info(log_indent_, "%s}", msg.c_str());
743 } else {
744 Log::Info(log_indent_, "Unsupported DX register display");
745 }
746
747 if (log_skip_execution_) {
748 return true;
749 }
750 }
751 cfa_ += (byte & 0x7) * 8 + 8;
752 return true;
753 }
754
DecodePrefix_11(uint8_t byte)755 inline bool ArmExidx::DecodePrefix_11(uint8_t byte) {
756 CHECK((byte >> 6) == 0x3);
757
758 switch ((byte >> 3) & 0x7) {
759 case 0:
760 return DecodePrefix_11_000(byte);
761 case 1:
762 return DecodePrefix_11_001(byte);
763 case 2:
764 return DecodePrefix_11_010(byte);
765 default:
766 // 11xxxyyy: Spare (xxx != 000, 001, 010)
767 if (log_type_ != ARM_LOG_NONE) {
768 Log::Info(log_indent_, "Spare");
769 }
770 status_ = ARM_STATUS_SPARE;
771 return false;
772 }
773 }
774
Decode()775 bool ArmExidx::Decode() {
776 status_ = ARM_STATUS_NONE;
777 uint8_t byte;
778 if (!GetByte(&byte)) {
779 return false;
780 }
781
782 switch (byte >> 6) {
783 case 0:
784 // 00xxxxxx: vsp = vsp + (xxxxxxx << 2) + 4
785 if (log_type_ != ARM_LOG_NONE) {
786 int32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
787 if (log_type_ == ARM_LOG_FULL) {
788 Log::Info(log_indent_, "vsp = vsp + %d", cfa_offset);
789 } else {
790 log_cfa_offset_ += cfa_offset;
791 }
792 AdjustRegisters(cfa_offset);
793
794 if (log_skip_execution_) {
795 break;
796 }
797 }
798 cfa_ += ((byte & 0x3f) << 2) + 4;
799 break;
800 case 1:
801 // 01xxxxxx: vsp = vsp - (xxxxxxx << 2) + 4
802 if (log_type_ != ARM_LOG_NONE) {
803 uint32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
804 if (log_type_ == ARM_LOG_FULL) {
805 Log::Info(log_indent_, "vsp = vsp - %d", cfa_offset);
806 } else {
807 log_cfa_offset_ -= cfa_offset;
808 }
809 AdjustRegisters(-cfa_offset);
810
811 if (log_skip_execution_) {
812 break;
813 }
814 }
815 cfa_ -= ((byte & 0x3f) << 2) + 4;
816 break;
817 case 2:
818 return DecodePrefix_10(byte);
819 default:
820 return DecodePrefix_11(byte);
821 }
822 return true;
823 }
824
Eval()825 bool ArmExidx::Eval() {
826 pc_set_ = false;
827 while (Decode());
828 return status_ == ARM_STATUS_FINISH;
829 }
830
LogByReg()831 void ArmExidx::LogByReg() {
832 if (log_type_ != ARM_LOG_BY_REG) {
833 return;
834 }
835
836 uint8_t cfa_reg;
837 if (log_regs_.count(LOG_CFA_REG) == 0) {
838 cfa_reg = 13;
839 } else {
840 cfa_reg = log_regs_[LOG_CFA_REG];
841 }
842
843 if (log_cfa_offset_ != 0) {
844 char sign = (log_cfa_offset_ > 0) ? '+' : '-';
845 Log::Info(log_indent_, "cfa = r%" PRIu8 " %c %d", cfa_reg, sign, abs(log_cfa_offset_));
846 } else {
847 Log::Info(log_indent_, "cfa = r%" PRIu8, cfa_reg);
848 }
849
850 for (const auto& entry : log_regs_) {
851 if (entry.first >= LOG_CFA_REG) {
852 break;
853 }
854 if (entry.second == 0) {
855 Log::Info(log_indent_, "r%" PRIu8 " = [cfa]", entry.first);
856 } else {
857 char sign = (entry.second > 0) ? '-' : '+';
858 Log::Info(log_indent_, "r%" PRIu8 " = [cfa %c %d]", entry.first, sign, abs(entry.second));
859 }
860 }
861 }
862
863 } // namespace unwindstack
864