blob: 6e397e31fa8e769648d23b04215d214e4f23ffa8 [file] [log] [blame]
Christopher Ferris723cf9b2017-01-19 20:08:48 -08001/*
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
Christopher Ferris723cf9b2017-01-19 20:08:48 -080017#include <stdint.h>
18
19#include <deque>
20#include <string>
21
22#include <android-base/stringprintf.h>
23
Christopher Ferrisd226a512017-07-14 10:37:19 -070024#include <unwindstack/Log.h>
Christopher Ferris53914162018-02-08 19:27:47 -080025#include <unwindstack/MachineArm.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070026#include <unwindstack/Memory.h>
Christopher Ferrisd06001d2017-11-30 18:56:01 -080027#include <unwindstack/RegsArm.h>
Christopher Ferrisd226a512017-07-14 10:37:19 -070028
Christopher Ferris723cf9b2017-01-19 20:08:48 -080029#include "ArmExidx.h"
Christopher Ferris94167032017-06-28 18:56:52 -070030#include "Check.h"
Christopher Ferrisd226a512017-07-14 10:37:19 -070031
32namespace unwindstack {
Christopher Ferris723cf9b2017-01-19 20:08:48 -080033
34void ArmExidx::LogRawData() {
35 std::string log_str("Raw Data:");
36 for (const uint8_t data : data_) {
37 log_str += android::base::StringPrintf(" 0x%02x", data);
38 }
39 log(log_indent_, log_str.c_str());
40}
41
42bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
43 data_.clear();
44 status_ = ARM_STATUS_NONE;
45
46 if (entry_offset & 1) {
47 // The offset needs to be at least two byte aligned.
48 status_ = ARM_STATUS_INVALID_ALIGNMENT;
49 return false;
50 }
51
52 // Each entry is a 32 bit prel31 offset followed by 32 bits
53 // of unwind information. If bit 31 of the unwind data is zero,
54 // then this is a prel31 offset to the start of the unwind data.
55 // If the unwind data is 1, then this is a cant unwind entry.
56 // Otherwise, this data is the compact form of the unwind information.
57 uint32_t data;
58 if (!elf_memory_->Read32(entry_offset + 4, &data)) {
59 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -080060 status_address_ = entry_offset + 4;
Christopher Ferris723cf9b2017-01-19 20:08:48 -080061 return false;
62 }
63 if (data == 1) {
64 // This is a CANT UNWIND entry.
65 status_ = ARM_STATUS_NO_UNWIND;
66 if (log_) {
67 log(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
68 log(log_indent_, "[cantunwind]");
69 }
70 return false;
71 }
72
73 if (data & (1UL << 31)) {
74 // This is a compact table entry.
75 if ((data >> 24) & 0xf) {
76 // This is a non-zero index, this code doesn't support
77 // other formats.
78 status_ = ARM_STATUS_INVALID_PERSONALITY;
79 return false;
80 }
81 data_.push_back((data >> 16) & 0xff);
82 data_.push_back((data >> 8) & 0xff);
83 uint8_t last_op = data & 0xff;
84 data_.push_back(last_op);
85 if (last_op != ARM_OP_FINISH) {
86 // If this didn't end with a finish op, add one.
87 data_.push_back(ARM_OP_FINISH);
88 }
89 if (log_) {
90 LogRawData();
91 }
92 return true;
93 }
94
95 // Get the address of the ops.
96 // Sign extend the data value if necessary.
97 int32_t signed_data = static_cast<int32_t>(data << 1) >> 1;
98 uint32_t addr = (entry_offset + 4) + signed_data;
99 if (!elf_memory_->Read32(addr, &data)) {
100 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800101 status_address_ = addr;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800102 return false;
103 }
104
105 size_t num_table_words;
106 if (data & (1UL << 31)) {
107 // Compact model.
108 switch ((data >> 24) & 0xf) {
109 case 0:
110 num_table_words = 0;
111 data_.push_back((data >> 16) & 0xff);
112 break;
113 case 1:
114 case 2:
115 num_table_words = (data >> 16) & 0xff;
116 addr += 4;
117 break;
118 default:
119 // Only a personality of 0, 1, 2 is valid.
120 status_ = ARM_STATUS_INVALID_PERSONALITY;
121 return false;
122 }
123 data_.push_back((data >> 8) & 0xff);
124 data_.push_back(data & 0xff);
125 } else {
126 // Generic model.
127
128 // Skip the personality routine data, it doesn't contain any data
129 // needed to decode the unwind information.
130 addr += 4;
131 if (!elf_memory_->Read32(addr, &data)) {
132 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800133 status_address_ = addr;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800134 return false;
135 }
136 num_table_words = (data >> 24) & 0xff;
137 data_.push_back((data >> 16) & 0xff);
138 data_.push_back((data >> 8) & 0xff);
139 data_.push_back(data & 0xff);
140 addr += 4;
141 }
142
143 if (num_table_words > 5) {
144 status_ = ARM_STATUS_MALFORMED;
145 return false;
146 }
147
148 for (size_t i = 0; i < num_table_words; i++) {
149 if (!elf_memory_->Read32(addr, &data)) {
150 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800151 status_address_ = addr;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800152 return false;
153 }
154 data_.push_back((data >> 24) & 0xff);
155 data_.push_back((data >> 16) & 0xff);
156 data_.push_back((data >> 8) & 0xff);
157 data_.push_back(data & 0xff);
158 addr += 4;
159 }
160
161 if (data_.back() != ARM_OP_FINISH) {
162 // If this didn't end with a finish op, add one.
163 data_.push_back(ARM_OP_FINISH);
164 }
165
166 if (log_) {
167 LogRawData();
168 }
169 return true;
170}
171
172inline bool ArmExidx::GetByte(uint8_t* byte) {
173 if (data_.empty()) {
174 status_ = ARM_STATUS_TRUNCATED;
175 return false;
176 }
177 *byte = data_.front();
178 data_.pop_front();
179 return true;
180}
181
182inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700183 CHECK((byte >> 4) == 0x8);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800184
185 uint16_t registers = (byte & 0xf) << 8;
186 if (!GetByte(&byte)) {
187 return false;
188 }
189
190 registers |= byte;
191 if (registers == 0) {
192 // 10000000 00000000: Refuse to unwind
193 if (log_) {
194 log(log_indent_, "Refuse to unwind");
195 }
196 status_ = ARM_STATUS_NO_UNWIND;
197 return false;
198 }
199 // 1000iiii iiiiiiii: Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
200 if (log_) {
201 bool add_comma = false;
202 std::string msg = "pop {";
203 for (size_t i = 0; i < 12; i++) {
204 if (registers & (1 << i)) {
205 if (add_comma) {
206 msg += ", ";
207 }
208 msg += android::base::StringPrintf("r%zu", i + 4);
209 add_comma = true;
210 }
211 }
212 log(log_indent_, "%s}", msg.c_str());
213 if (log_skip_execution_) {
214 return true;
215 }
216 }
217
218 registers <<= 4;
219 for (size_t reg = 4; reg < 16; reg++) {
220 if (registers & (1 << reg)) {
221 if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
222 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800223 status_address_ = cfa_;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800224 return false;
225 }
226 cfa_ += 4;
227 }
228 }
Christopher Ferris3958f802017-02-01 15:44:40 -0800229
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800230 // If the sp register is modified, change the cfa value.
231 if (registers & (1 << ARM_REG_SP)) {
232 cfa_ = (*regs_)[ARM_REG_SP];
233 }
Christopher Ferris3958f802017-02-01 15:44:40 -0800234
235 // Indicate if the pc register was set.
236 if (registers & (1 << ARM_REG_PC)) {
237 pc_set_ = true;
238 }
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800239 return true;
240}
241
242inline bool ArmExidx::DecodePrefix_10_01(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700243 CHECK((byte >> 4) == 0x9);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800244
245 uint8_t bits = byte & 0xf;
246 if (bits == 13 || bits == 15) {
247 // 10011101: Reserved as prefix for ARM register to register moves
248 // 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
249 if (log_) {
250 log(log_indent_, "[Reserved]");
251 }
252 status_ = ARM_STATUS_RESERVED;
253 return false;
254 }
255 // 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
256 if (log_) {
257 log(log_indent_, "vsp = r%d", bits);
258 if (log_skip_execution_) {
259 return true;
260 }
261 }
262 // It is impossible for bits to be larger than the total number of
263 // arm registers, so don't bother checking if bits is a valid register.
264 cfa_ = (*regs_)[bits];
265 return true;
266}
267
268inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700269 CHECK((byte >> 4) == 0xa);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800270
271 // 10100nnn: Pop r4-r[4+nnn]
272 // 10101nnn: Pop r4-r[4+nnn], r14
273 if (log_) {
274 std::string msg = "pop {r4";
275 uint8_t end_reg = byte & 0x7;
276 if (end_reg) {
277 msg += android::base::StringPrintf("-r%d", 4 + end_reg);
278 }
279 if (byte & 0x8) {
280 log(log_indent_, "%s, r14}", msg.c_str());
281 } else {
282 log(log_indent_, "%s}", msg.c_str());
283 }
284 if (log_skip_execution_) {
285 return true;
286 }
287 }
288
289 for (size_t i = 4; i <= 4 + (byte & 0x7); i++) {
290 if (!process_memory_->Read32(cfa_, &(*regs_)[i])) {
291 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800292 status_address_ = cfa_;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800293 return false;
294 }
295 cfa_ += 4;
296 }
297 if (byte & 0x8) {
298 if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) {
299 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800300 status_address_ = cfa_;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800301 return false;
302 }
303 cfa_ += 4;
304 }
305 return true;
306}
307
308inline bool ArmExidx::DecodePrefix_10_11_0000() {
309 // 10110000: Finish
310 if (log_) {
311 log(log_indent_, "finish");
312 if (log_skip_execution_) {
313 status_ = ARM_STATUS_FINISH;
314 return false;
315 }
316 }
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800317 status_ = ARM_STATUS_FINISH;
318 return false;
319}
320
321inline bool ArmExidx::DecodePrefix_10_11_0001() {
322 uint8_t byte;
323 if (!GetByte(&byte)) {
324 return false;
325 }
326
327 if (byte == 0) {
328 // 10110001 00000000: Spare
329 if (log_) {
330 log(log_indent_, "Spare");
331 }
332 status_ = ARM_STATUS_SPARE;
333 return false;
334 }
335 if (byte >> 4) {
336 // 10110001 xxxxyyyy: Spare (xxxx != 0000)
337 if (log_) {
338 log(log_indent_, "Spare");
339 }
340 status_ = ARM_STATUS_SPARE;
341 return false;
342 }
343
344 // 10110001 0000iiii: Pop integer registers under mask {r3, r2, r1, r0}
345 if (log_) {
346 bool add_comma = false;
347 std::string msg = "pop {";
348 for (size_t i = 0; i < 4; i++) {
349 if (byte & (1 << i)) {
350 if (add_comma) {
351 msg += ", ";
352 }
353 msg += android::base::StringPrintf("r%zu", i);
354 add_comma = true;
355 }
356 }
357 log(log_indent_, "%s}", msg.c_str());
358 if (log_skip_execution_) {
359 return true;
360 }
361 }
362
363 for (size_t reg = 0; reg < 4; reg++) {
364 if (byte & (1 << reg)) {
365 if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
366 status_ = ARM_STATUS_READ_FAILED;
Christopher Ferris2fcf4cf2018-01-23 17:52:23 -0800367 status_address_ = cfa_;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800368 return false;
369 }
370 cfa_ += 4;
371 }
372 }
373 return true;
374}
375
376inline bool ArmExidx::DecodePrefix_10_11_0010() {
377 // 10110010 uleb128: vsp = vsp + 0x204 + (uleb128 << 2)
378 uint32_t result = 0;
379 uint32_t shift = 0;
380 uint8_t byte;
381 do {
382 if (!GetByte(&byte)) {
383 return false;
384 }
385
386 result |= (byte & 0x7f) << shift;
387 shift += 7;
388 } while (byte & 0x80);
389 result <<= 2;
390 if (log_) {
391 log(log_indent_, "vsp = vsp + %d", 0x204 + result);
392 if (log_skip_execution_) {
393 return true;
394 }
395 }
396 cfa_ += 0x204 + result;
397 return true;
398}
399
400inline bool ArmExidx::DecodePrefix_10_11_0011() {
401 // 10110011 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX
402 uint8_t byte;
403 if (!GetByte(&byte)) {
404 return false;
405 }
406
407 if (log_) {
408 uint8_t start_reg = byte >> 4;
409 std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
410 uint8_t end_reg = start_reg + (byte & 0xf);
411 if (end_reg) {
412 msg += android::base::StringPrintf("-d%d", end_reg);
413 }
414 log(log_indent_, "%s}", msg.c_str());
415 if (log_skip_execution_) {
416 return true;
417 }
418 }
419 cfa_ += (byte & 0xf) * 8 + 12;
420 return true;
421}
422
423inline bool ArmExidx::DecodePrefix_10_11_01nn() {
424 // 101101nn: Spare
425 if (log_) {
426 log(log_indent_, "Spare");
427 }
428 status_ = ARM_STATUS_SPARE;
429 return false;
430}
431
432inline bool ArmExidx::DecodePrefix_10_11_1nnn(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700433 CHECK((byte & ~0x07) == 0xb8);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800434
435 // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
436 if (log_) {
437 std::string msg = "pop {d8";
438 uint8_t last_reg = (byte & 0x7);
439 if (last_reg) {
440 msg += android::base::StringPrintf("-d%d", last_reg + 8);
441 }
442 log(log_indent_, "%s}", msg.c_str());
443 if (log_skip_execution_) {
444 return true;
445 }
446 }
447 // Only update the cfa.
448 cfa_ += (byte & 0x7) * 8 + 12;
449 return true;
450}
451
452inline bool ArmExidx::DecodePrefix_10(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700453 CHECK((byte >> 6) == 0x2);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800454
455 switch ((byte >> 4) & 0x3) {
456 case 0:
457 return DecodePrefix_10_00(byte);
458 case 1:
459 return DecodePrefix_10_01(byte);
460 case 2:
461 return DecodePrefix_10_10(byte);
462 default:
463 switch (byte & 0xf) {
464 case 0:
465 return DecodePrefix_10_11_0000();
466 case 1:
467 return DecodePrefix_10_11_0001();
468 case 2:
469 return DecodePrefix_10_11_0010();
470 case 3:
471 return DecodePrefix_10_11_0011();
472 default:
473 if (byte & 0x8) {
474 return DecodePrefix_10_11_1nnn(byte);
475 } else {
476 return DecodePrefix_10_11_01nn();
477 }
478 }
479 }
480}
481
482inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700483 CHECK((byte & ~0x07) == 0xc0);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800484
485 uint8_t bits = byte & 0x7;
486 if (bits == 6) {
487 if (!GetByte(&byte)) {
488 return false;
489 }
490
491 // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]
492 if (log_) {
493 uint8_t start_reg = byte >> 4;
494 std::string msg = android::base::StringPrintf("pop {wR%d", start_reg);
495 uint8_t end_reg = byte & 0xf;
496 if (end_reg) {
497 msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
498 }
499 log(log_indent_, "%s}", msg.c_str());
500 if (log_skip_execution_) {
501 return true;
502 }
503 }
504 // Only update the cfa.
505 cfa_ += (byte & 0xf) * 8 + 8;
506 } else if (bits == 7) {
507 if (!GetByte(&byte)) {
508 return false;
509 }
510
511 if (byte == 0) {
512 // 11000111 00000000: Spare
513 if (log_) {
514 log(log_indent_, "Spare");
515 }
516 status_ = ARM_STATUS_SPARE;
517 return false;
518 } else if ((byte >> 4) == 0) {
519 // 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
520 if (log_) {
521 bool add_comma = false;
522 std::string msg = "pop {";
523 for (size_t i = 0; i < 4; i++) {
524 if (byte & (1 << i)) {
525 if (add_comma) {
526 msg += ", ";
527 }
528 msg += android::base::StringPrintf("wCGR%zu", i);
529 add_comma = true;
530 }
531 }
532 log(log_indent_, "%s}", msg.c_str());
533 }
534 // Only update the cfa.
535 cfa_ += __builtin_popcount(byte) * 4;
536 } else {
537 // 11000111 xxxxyyyy: Spare (xxxx != 0000)
538 if (log_) {
539 log(log_indent_, "Spare");
540 }
541 status_ = ARM_STATUS_SPARE;
542 return false;
543 }
544 } else {
545 // 11000nnn: Intel Wireless MMX pop wR[10]-wR[10+nnn] (nnn != 6, 7)
546 if (log_) {
547 std::string msg = "pop {wR10";
548 uint8_t nnn = byte & 0x7;
549 if (nnn) {
550 msg += android::base::StringPrintf("-wR%d", 10 + nnn);
551 }
552 log(log_indent_, "%s}", msg.c_str());
553 if (log_skip_execution_) {
554 return true;
555 }
556 }
557 // Only update the cfa.
558 cfa_ += (byte & 0x7) * 8 + 8;
559 }
560 return true;
561}
562
563inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700564 CHECK((byte & ~0x07) == 0xc8);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800565
566 uint8_t bits = byte & 0x7;
567 if (bits == 0) {
568 // 11001000 sssscccc: Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] by VPUSH
569 if (!GetByte(&byte)) {
570 return false;
571 }
572
573 if (log_) {
574 uint8_t start_reg = byte >> 4;
575 std::string msg = android::base::StringPrintf("pop {d%d", 16 + start_reg);
576 uint8_t end_reg = byte & 0xf;
577 if (end_reg) {
578 msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
579 }
580 log(log_indent_, "%s}", msg.c_str());
581 if (log_skip_execution_) {
582 return true;
583 }
584 }
585 // Only update the cfa.
586 cfa_ += (byte & 0xf) * 8 + 8;
587 } else if (bits == 1) {
588 // 11001001 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by VPUSH
589 if (!GetByte(&byte)) {
590 return false;
591 }
592
593 if (log_) {
594 uint8_t start_reg = byte >> 4;
595 std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
596 uint8_t end_reg = byte & 0xf;
597 if (end_reg) {
598 msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
599 }
600 log(log_indent_, "%s}", msg.c_str());
601 if (log_skip_execution_) {
602 return true;
603 }
604 }
605 // Only update the cfa.
606 cfa_ += (byte & 0xf) * 8 + 8;
607 } else {
608 // 11001yyy: Spare (yyy != 000, 001)
609 if (log_) {
610 log(log_indent_, "Spare");
611 }
612 status_ = ARM_STATUS_SPARE;
613 return false;
614 }
615 return true;
616}
617
618inline bool ArmExidx::DecodePrefix_11_010(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700619 CHECK((byte & ~0x07) == 0xd0);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800620
621 // 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
622 if (log_) {
623 std::string msg = "pop {d8";
624 uint8_t end_reg = byte & 0x7;
625 if (end_reg) {
626 msg += android::base::StringPrintf("-d%d", 8 + end_reg);
627 }
628 log(log_indent_, "%s}", msg.c_str());
629 if (log_skip_execution_) {
630 return true;
631 }
632 }
633 cfa_ += (byte & 0x7) * 8 + 8;
634 return true;
635}
636
637inline bool ArmExidx::DecodePrefix_11(uint8_t byte) {
Christopher Ferris94167032017-06-28 18:56:52 -0700638 CHECK((byte >> 6) == 0x3);
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800639
640 switch ((byte >> 3) & 0x7) {
641 case 0:
642 return DecodePrefix_11_000(byte);
643 case 1:
644 return DecodePrefix_11_001(byte);
645 case 2:
646 return DecodePrefix_11_010(byte);
647 default:
648 // 11xxxyyy: Spare (xxx != 000, 001, 010)
649 if (log_) {
650 log(log_indent_, "Spare");
651 }
652 status_ = ARM_STATUS_SPARE;
653 return false;
654 }
655}
656
657bool ArmExidx::Decode() {
658 status_ = ARM_STATUS_NONE;
659 uint8_t byte;
660 if (!GetByte(&byte)) {
661 return false;
662 }
663
664 switch (byte >> 6) {
665 case 0:
666 // 00xxxxxx: vsp = vsp + (xxxxxxx << 2) + 4
667 if (log_) {
668 log(log_indent_, "vsp = vsp + %d", ((byte & 0x3f) << 2) + 4);
669 if (log_skip_execution_) {
670 break;
671 }
672 }
673 cfa_ += ((byte & 0x3f) << 2) + 4;
674 break;
675 case 1:
676 // 01xxxxxx: vsp = vsp - (xxxxxxx << 2) + 4
677 if (log_) {
678 log(log_indent_, "vsp = vsp - %d", ((byte & 0x3f) << 2) + 4);
679 if (log_skip_execution_) {
680 break;
681 }
682 }
683 cfa_ -= ((byte & 0x3f) << 2) + 4;
684 break;
685 case 2:
686 return DecodePrefix_10(byte);
687 default:
688 return DecodePrefix_11(byte);
689 }
690 return true;
691}
692
693bool ArmExidx::Eval() {
Christopher Ferris3958f802017-02-01 15:44:40 -0800694 pc_set_ = false;
Christopher Ferris723cf9b2017-01-19 20:08:48 -0800695 while (Decode());
696 return status_ == ARM_STATUS_FINISH;
697}
Christopher Ferrisd226a512017-07-14 10:37:19 -0700698
699} // namespace unwindstack