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