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