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