1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <elf.h> 18 #include <stdint.h> 19 20 #include <unwindstack/MachineArm.h> 21 #include <unwindstack/Memory.h> 22 #include <unwindstack/RegsArm.h> 23 24 #include "ArmExidx.h" 25 #include "ElfInterfaceArm.h" 26 27 namespace unwindstack { 28 29 bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) { 30 if (start_offset_ == 0 || total_entries_ == 0) { 31 last_error_.code = ERROR_UNWIND_INFO; 32 return false; 33 } 34 35 size_t first = 0; 36 size_t last = total_entries_; 37 while (first < last) { 38 size_t current = (first + last) / 2; 39 uint32_t addr = addrs_[current]; 40 if (addr == 0) { 41 if (!GetPrel31Addr(start_offset_ + current * 8, &addr)) { 42 return false; 43 } 44 addrs_[current] = addr; 45 } 46 if (pc == addr) { 47 *entry_offset = start_offset_ + current * 8; 48 return true; 49 } 50 if (pc < addr) { 51 last = current; 52 } else { 53 first = current + 1; 54 } 55 } 56 if (last != 0) { 57 *entry_offset = start_offset_ + (last - 1) * 8; 58 return true; 59 } 60 last_error_.code = ERROR_UNWIND_INFO; 61 return false; 62 } 63 64 bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) { 65 uint32_t data; 66 if (!memory_->Read32(offset, &data)) { 67 last_error_.code = ERROR_MEMORY_INVALID; 68 last_error_.address = offset; 69 return false; 70 } 71 72 // Sign extend the value if necessary. 73 int32_t value = (static_cast<int32_t>(data) << 1) >> 1; 74 *addr = offset + value; 75 return true; 76 } 77 78 #if !defined(PT_ARM_EXIDX) 79 #define PT_ARM_EXIDX 0x70000001 80 #endif 81 82 bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) { 83 if (type != PT_ARM_EXIDX) { 84 return false; 85 } 86 87 Elf32_Phdr phdr; 88 if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) { 89 return true; 90 } 91 if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) { 92 return true; 93 } 94 start_offset_ = phdr.p_vaddr - load_bias; 95 total_entries_ = phdr.p_memsz / 8; 96 return true; 97 } 98 99 bool ElfInterfaceArm::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory, 100 bool* finished) { 101 // Dwarf unwind information is precise about whether a pc is covered or not, 102 // but arm unwind information only has ranges of pc. In order to avoid 103 // incorrectly doing a bad unwind using arm unwind information for a 104 // different function, always try and unwind with the dwarf information first. 105 return ElfInterface32::Step(pc, load_bias, regs, process_memory, finished) || 106 StepExidx(pc, load_bias, regs, process_memory, finished); 107 } 108 109 bool ElfInterfaceArm::StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory, 110 bool* finished) { 111 // Adjust the load bias to get the real relative pc. 112 if (pc < load_bias) { 113 last_error_.code = ERROR_UNWIND_INFO; 114 return false; 115 } 116 pc -= load_bias; 117 118 RegsArm* regs_arm = reinterpret_cast<RegsArm*>(regs); 119 uint64_t entry_offset; 120 if (!FindEntry(pc, &entry_offset)) { 121 return false; 122 } 123 124 ArmExidx arm(regs_arm, memory_, process_memory); 125 arm.set_cfa(regs_arm->sp()); 126 bool return_value = false; 127 if (arm.ExtractEntryData(entry_offset) && arm.Eval()) { 128 // If the pc was not set, then use the LR registers for the PC. 129 if (!arm.pc_set()) { 130 (*regs_arm)[ARM_REG_PC] = (*regs_arm)[ARM_REG_LR]; 131 } 132 (*regs_arm)[ARM_REG_SP] = arm.cfa(); 133 return_value = true; 134 135 // If the pc was set to zero, consider this the final frame. 136 *finished = (regs_arm->pc() == 0) ? true : false; 137 } 138 139 if (arm.status() == ARM_STATUS_NO_UNWIND) { 140 *finished = true; 141 return true; 142 } 143 144 if (!return_value) { 145 switch (arm.status()) { 146 case ARM_STATUS_NONE: 147 case ARM_STATUS_NO_UNWIND: 148 case ARM_STATUS_FINISH: 149 last_error_.code = ERROR_NONE; 150 break; 151 152 case ARM_STATUS_RESERVED: 153 case ARM_STATUS_SPARE: 154 case ARM_STATUS_TRUNCATED: 155 case ARM_STATUS_MALFORMED: 156 case ARM_STATUS_INVALID_ALIGNMENT: 157 case ARM_STATUS_INVALID_PERSONALITY: 158 last_error_.code = ERROR_UNWIND_INFO; 159 break; 160 161 case ARM_STATUS_READ_FAILED: 162 last_error_.code = ERROR_MEMORY_INVALID; 163 last_error_.address = arm.status_address(); 164 break; 165 } 166 } 167 return return_value; 168 } 169 170 bool ElfInterfaceArm::GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name, 171 uint64_t* offset) { 172 // For ARM, thumb function symbols have bit 0 set, but the address passed 173 // in here might not have this bit set and result in a failure to find 174 // the thumb function names. Adjust the address and offset to account 175 // for this possible case. 176 if (ElfInterface32::GetFunctionName(addr | 1, load_bias, name, offset)) { 177 *offset &= ~1; 178 return true; 179 } 180 return false; 181 } 182 183 } // namespace unwindstack 184