xref: /aosp_15_r20/system/unwinding/libunwindstack/ElfInterfaceArm.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 <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