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 <elf.h>
18*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
19*eb293b8fSAndroid Build Coastguard Worker
20*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/MachineArm.h>
21*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Memory.h>
22*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/RegsArm.h>
23*eb293b8fSAndroid Build Coastguard Worker
24*eb293b8fSAndroid Build Coastguard Worker #include "ArmExidx.h"
25*eb293b8fSAndroid Build Coastguard Worker #include "ElfInterfaceArm.h"
26*eb293b8fSAndroid Build Coastguard Worker
27*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
28*eb293b8fSAndroid Build Coastguard Worker
Init(int64_t * load_bias)29*eb293b8fSAndroid Build Coastguard Worker bool ElfInterfaceArm::Init(int64_t* load_bias) {
30*eb293b8fSAndroid Build Coastguard Worker if (!ElfInterface32::Init(load_bias)) {
31*eb293b8fSAndroid Build Coastguard Worker return false;
32*eb293b8fSAndroid Build Coastguard Worker }
33*eb293b8fSAndroid Build Coastguard Worker load_bias_ = *load_bias;
34*eb293b8fSAndroid Build Coastguard Worker return true;
35*eb293b8fSAndroid Build Coastguard Worker }
36*eb293b8fSAndroid Build Coastguard Worker
FindEntry(uint32_t pc,uint64_t * entry_offset)37*eb293b8fSAndroid Build Coastguard Worker bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
38*eb293b8fSAndroid Build Coastguard Worker if (start_offset_ == 0 || total_entries_ == 0) {
39*eb293b8fSAndroid Build Coastguard Worker last_error_.code = ERROR_UNWIND_INFO;
40*eb293b8fSAndroid Build Coastguard Worker return false;
41*eb293b8fSAndroid Build Coastguard Worker }
42*eb293b8fSAndroid Build Coastguard Worker
43*eb293b8fSAndroid Build Coastguard Worker size_t first = 0;
44*eb293b8fSAndroid Build Coastguard Worker size_t last = total_entries_;
45*eb293b8fSAndroid Build Coastguard Worker while (first < last) {
46*eb293b8fSAndroid Build Coastguard Worker size_t current = (first + last) / 2;
47*eb293b8fSAndroid Build Coastguard Worker uint32_t addr = addrs_[current];
48*eb293b8fSAndroid Build Coastguard Worker if (addr == 0) {
49*eb293b8fSAndroid Build Coastguard Worker if (!GetPrel31Addr(start_offset_ + current * 8, &addr)) {
50*eb293b8fSAndroid Build Coastguard Worker return false;
51*eb293b8fSAndroid Build Coastguard Worker }
52*eb293b8fSAndroid Build Coastguard Worker addrs_[current] = addr;
53*eb293b8fSAndroid Build Coastguard Worker }
54*eb293b8fSAndroid Build Coastguard Worker if (pc == addr) {
55*eb293b8fSAndroid Build Coastguard Worker *entry_offset = start_offset_ + current * 8;
56*eb293b8fSAndroid Build Coastguard Worker return true;
57*eb293b8fSAndroid Build Coastguard Worker }
58*eb293b8fSAndroid Build Coastguard Worker if (pc < addr) {
59*eb293b8fSAndroid Build Coastguard Worker last = current;
60*eb293b8fSAndroid Build Coastguard Worker } else {
61*eb293b8fSAndroid Build Coastguard Worker first = current + 1;
62*eb293b8fSAndroid Build Coastguard Worker }
63*eb293b8fSAndroid Build Coastguard Worker }
64*eb293b8fSAndroid Build Coastguard Worker if (last != 0) {
65*eb293b8fSAndroid Build Coastguard Worker *entry_offset = start_offset_ + (last - 1) * 8;
66*eb293b8fSAndroid Build Coastguard Worker return true;
67*eb293b8fSAndroid Build Coastguard Worker }
68*eb293b8fSAndroid Build Coastguard Worker last_error_.code = ERROR_UNWIND_INFO;
69*eb293b8fSAndroid Build Coastguard Worker return false;
70*eb293b8fSAndroid Build Coastguard Worker }
71*eb293b8fSAndroid Build Coastguard Worker
GetPrel31Addr(uint32_t offset,uint32_t * addr)72*eb293b8fSAndroid Build Coastguard Worker bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) {
73*eb293b8fSAndroid Build Coastguard Worker uint32_t data;
74*eb293b8fSAndroid Build Coastguard Worker if (!memory_->Read32(offset, &data)) {
75*eb293b8fSAndroid Build Coastguard Worker last_error_.code = ERROR_MEMORY_INVALID;
76*eb293b8fSAndroid Build Coastguard Worker last_error_.address = offset;
77*eb293b8fSAndroid Build Coastguard Worker return false;
78*eb293b8fSAndroid Build Coastguard Worker }
79*eb293b8fSAndroid Build Coastguard Worker
80*eb293b8fSAndroid Build Coastguard Worker // Sign extend the value if necessary.
81*eb293b8fSAndroid Build Coastguard Worker int32_t value = (static_cast<int32_t>(data) << 1) >> 1;
82*eb293b8fSAndroid Build Coastguard Worker *addr = offset + value;
83*eb293b8fSAndroid Build Coastguard Worker return true;
84*eb293b8fSAndroid Build Coastguard Worker }
85*eb293b8fSAndroid Build Coastguard Worker
HandleUnknownType(uint32_t type,uint64_t ph_offset,uint64_t ph_filesz)86*eb293b8fSAndroid Build Coastguard Worker void ElfInterfaceArm::HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) {
87*eb293b8fSAndroid Build Coastguard Worker if (type != PT_ARM_EXIDX) {
88*eb293b8fSAndroid Build Coastguard Worker return;
89*eb293b8fSAndroid Build Coastguard Worker }
90*eb293b8fSAndroid Build Coastguard Worker
91*eb293b8fSAndroid Build Coastguard Worker // The offset already takes into account the load bias.
92*eb293b8fSAndroid Build Coastguard Worker start_offset_ = ph_offset;
93*eb293b8fSAndroid Build Coastguard Worker
94*eb293b8fSAndroid Build Coastguard Worker // Always use filesz instead of memsz. In most cases they are the same,
95*eb293b8fSAndroid Build Coastguard Worker // but some shared libraries wind up setting one correctly and not the other.
96*eb293b8fSAndroid Build Coastguard Worker total_entries_ = ph_filesz / 8;
97*eb293b8fSAndroid Build Coastguard Worker }
98*eb293b8fSAndroid Build Coastguard Worker
Step(uint64_t pc,Regs * regs,Memory * process_memory,bool * finished,bool * is_signal_frame)99*eb293b8fSAndroid Build Coastguard Worker bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
100*eb293b8fSAndroid Build Coastguard Worker bool* is_signal_frame) {
101*eb293b8fSAndroid Build Coastguard Worker // Dwarf unwind information is precise about whether a pc is covered or not,
102*eb293b8fSAndroid Build Coastguard Worker // but arm unwind information only has ranges of pc. In order to avoid
103*eb293b8fSAndroid Build Coastguard Worker // incorrectly doing a bad unwind using arm unwind information for a
104*eb293b8fSAndroid Build Coastguard Worker // different function, always try and unwind with the dwarf information first.
105*eb293b8fSAndroid Build Coastguard Worker return ElfInterface32::Step(pc, regs, process_memory, finished, is_signal_frame) ||
106*eb293b8fSAndroid Build Coastguard Worker StepExidx(pc, regs, process_memory, finished);
107*eb293b8fSAndroid Build Coastguard Worker }
108*eb293b8fSAndroid Build Coastguard Worker
StepExidx(uint64_t pc,Regs * regs,Memory * process_memory,bool * finished)109*eb293b8fSAndroid Build Coastguard Worker bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
110*eb293b8fSAndroid Build Coastguard Worker // Adjust the load bias to get the real relative pc.
111*eb293b8fSAndroid Build Coastguard Worker if (pc < load_bias_) {
112*eb293b8fSAndroid Build Coastguard Worker last_error_.code = ERROR_UNWIND_INFO;
113*eb293b8fSAndroid Build Coastguard Worker return false;
114*eb293b8fSAndroid Build Coastguard Worker }
115*eb293b8fSAndroid Build Coastguard Worker pc -= load_bias_;
116*eb293b8fSAndroid Build Coastguard Worker
117*eb293b8fSAndroid Build Coastguard Worker RegsArm* regs_arm = reinterpret_cast<RegsArm*>(regs);
118*eb293b8fSAndroid Build Coastguard Worker uint64_t entry_offset;
119*eb293b8fSAndroid Build Coastguard Worker if (!FindEntry(pc, &entry_offset)) {
120*eb293b8fSAndroid Build Coastguard Worker return false;
121*eb293b8fSAndroid Build Coastguard Worker }
122*eb293b8fSAndroid Build Coastguard Worker
123*eb293b8fSAndroid Build Coastguard Worker ArmExidx arm(regs_arm, memory_.get(), process_memory);
124*eb293b8fSAndroid Build Coastguard Worker arm.set_cfa(regs_arm->sp());
125*eb293b8fSAndroid Build Coastguard Worker bool return_value = false;
126*eb293b8fSAndroid Build Coastguard Worker if (arm.ExtractEntryData(entry_offset) && arm.Eval()) {
127*eb293b8fSAndroid Build Coastguard Worker // If the pc was not set, then use the LR registers for the PC.
128*eb293b8fSAndroid Build Coastguard Worker if (!arm.pc_set()) {
129*eb293b8fSAndroid Build Coastguard Worker (*regs_arm)[ARM_REG_PC] = (*regs_arm)[ARM_REG_LR];
130*eb293b8fSAndroid Build Coastguard Worker }
131*eb293b8fSAndroid Build Coastguard Worker (*regs_arm)[ARM_REG_SP] = arm.cfa();
132*eb293b8fSAndroid Build Coastguard Worker return_value = true;
133*eb293b8fSAndroid Build Coastguard Worker
134*eb293b8fSAndroid Build Coastguard Worker // If the pc was set to zero, consider this the final frame.
135*eb293b8fSAndroid Build Coastguard Worker *finished = (regs_arm->pc() == 0) ? true : false;
136*eb293b8fSAndroid Build Coastguard Worker }
137*eb293b8fSAndroid Build Coastguard Worker
138*eb293b8fSAndroid Build Coastguard Worker if (arm.status() == ARM_STATUS_NO_UNWIND) {
139*eb293b8fSAndroid Build Coastguard Worker *finished = true;
140*eb293b8fSAndroid Build Coastguard Worker return true;
141*eb293b8fSAndroid Build Coastguard Worker }
142*eb293b8fSAndroid Build Coastguard Worker
143*eb293b8fSAndroid Build Coastguard Worker if (!return_value) {
144*eb293b8fSAndroid Build Coastguard Worker switch (arm.status()) {
145*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_NONE:
146*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_NO_UNWIND:
147*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_FINISH:
148*eb293b8fSAndroid Build Coastguard Worker last_error_.code = ERROR_NONE;
149*eb293b8fSAndroid Build Coastguard Worker break;
150*eb293b8fSAndroid Build Coastguard Worker
151*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_RESERVED:
152*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_SPARE:
153*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_TRUNCATED:
154*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_MALFORMED:
155*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_INVALID_ALIGNMENT:
156*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_INVALID_PERSONALITY:
157*eb293b8fSAndroid Build Coastguard Worker last_error_.code = ERROR_UNWIND_INFO;
158*eb293b8fSAndroid Build Coastguard Worker break;
159*eb293b8fSAndroid Build Coastguard Worker
160*eb293b8fSAndroid Build Coastguard Worker case ARM_STATUS_READ_FAILED:
161*eb293b8fSAndroid Build Coastguard Worker last_error_.code = ERROR_MEMORY_INVALID;
162*eb293b8fSAndroid Build Coastguard Worker last_error_.address = arm.status_address();
163*eb293b8fSAndroid Build Coastguard Worker break;
164*eb293b8fSAndroid Build Coastguard Worker }
165*eb293b8fSAndroid Build Coastguard Worker }
166*eb293b8fSAndroid Build Coastguard Worker return return_value;
167*eb293b8fSAndroid Build Coastguard Worker }
168*eb293b8fSAndroid Build Coastguard Worker
GetFunctionName(uint64_t addr,SharedString * name,uint64_t * offset)169*eb293b8fSAndroid Build Coastguard Worker bool ElfInterfaceArm::GetFunctionName(uint64_t addr, SharedString* name, uint64_t* offset) {
170*eb293b8fSAndroid Build Coastguard Worker // For ARM, thumb function symbols have bit 0 set, but the address passed
171*eb293b8fSAndroid Build Coastguard Worker // in here might not have this bit set and result in a failure to find
172*eb293b8fSAndroid Build Coastguard Worker // the thumb function names. Adjust the address and offset to account
173*eb293b8fSAndroid Build Coastguard Worker // for this possible case.
174*eb293b8fSAndroid Build Coastguard Worker if (ElfInterface32::GetFunctionName(addr | 1, name, offset)) {
175*eb293b8fSAndroid Build Coastguard Worker *offset &= ~1;
176*eb293b8fSAndroid Build Coastguard Worker return true;
177*eb293b8fSAndroid Build Coastguard Worker }
178*eb293b8fSAndroid Build Coastguard Worker return false;
179*eb293b8fSAndroid Build Coastguard Worker }
180*eb293b8fSAndroid Build Coastguard Worker
181*eb293b8fSAndroid Build Coastguard Worker } // namespace unwindstack
182