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 <stdint.h> 18 19#include <functional> 20 21#include <unwindstack/Elf.h> 22#include <unwindstack/MachineArm.h> 23#include <unwindstack/MapInfo.h> 24#include <unwindstack/Memory.h> 25#include <unwindstack/RegsArm.h> 26#include <unwindstack/UcontextArm.h> 27#include <unwindstack/UserArm.h> 28 29namespace unwindstack { 30 31RegsArm::RegsArm() : RegsImpl<uint32_t>(ARM_REG_LAST, Location(LOCATION_REGISTER, ARM_REG_LR)) {} 32 33ArchEnum RegsArm::Arch() { 34 return ARCH_ARM; 35} 36 37uint64_t RegsArm::pc() { 38 return regs_[ARM_REG_PC]; 39} 40 41uint64_t RegsArm::sp() { 42 return regs_[ARM_REG_SP]; 43} 44 45void RegsArm::set_pc(uint64_t pc) { 46 regs_[ARM_REG_PC] = pc; 47} 48 49void RegsArm::set_sp(uint64_t sp) { 50 regs_[ARM_REG_SP] = sp; 51} 52 53uint64_t RegsArm::GetPcAdjustment(uint64_t rel_pc, Elf* elf) { 54 if (!elf->valid()) { 55 return 2; 56 } 57 58 uint64_t load_bias = elf->GetLoadBias(); 59 if (rel_pc < load_bias) { 60 if (rel_pc < 2) { 61 return 0; 62 } 63 return 2; 64 } 65 uint64_t adjusted_rel_pc = rel_pc - load_bias; 66 if (adjusted_rel_pc < 5) { 67 if (adjusted_rel_pc < 2) { 68 return 0; 69 } 70 return 2; 71 } 72 73 if (adjusted_rel_pc & 1) { 74 // This is a thumb instruction, it could be 2 or 4 bytes. 75 uint32_t value; 76 if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) || 77 (value & 0xe000f000) != 0xe000f000) { 78 return 2; 79 } 80 } 81 return 4; 82} 83 84bool RegsArm::SetPcFromReturnAddress(Memory*) { 85 uint32_t lr = regs_[ARM_REG_LR]; 86 if (regs_[ARM_REG_PC] == lr) { 87 return false; 88 } 89 90 regs_[ARM_REG_PC] = lr; 91 return true; 92} 93 94void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) { 95 fn("r0", regs_[ARM_REG_R0]); 96 fn("r1", regs_[ARM_REG_R1]); 97 fn("r2", regs_[ARM_REG_R2]); 98 fn("r3", regs_[ARM_REG_R3]); 99 fn("r4", regs_[ARM_REG_R4]); 100 fn("r5", regs_[ARM_REG_R5]); 101 fn("r6", regs_[ARM_REG_R6]); 102 fn("r7", regs_[ARM_REG_R7]); 103 fn("r8", regs_[ARM_REG_R8]); 104 fn("r9", regs_[ARM_REG_R9]); 105 fn("r10", regs_[ARM_REG_R10]); 106 fn("r11", regs_[ARM_REG_R11]); 107 fn("ip", regs_[ARM_REG_R12]); 108 fn("sp", regs_[ARM_REG_SP]); 109 fn("lr", regs_[ARM_REG_LR]); 110 fn("pc", regs_[ARM_REG_PC]); 111} 112 113Regs* RegsArm::Read(void* remote_data) { 114 arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data); 115 116 RegsArm* regs = new RegsArm(); 117 memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t)); 118 return regs; 119} 120 121Regs* RegsArm::CreateFromUcontext(void* ucontext) { 122 arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext); 123 124 RegsArm* regs = new RegsArm(); 125 memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t)); 126 return regs; 127} 128 129bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { 130 uint32_t data; 131 Memory* elf_memory = elf->memory(); 132 // Read from elf memory since it is usually more expensive to read from 133 // process memory. 134 if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) { 135 return false; 136 } 137 138 uint64_t offset = 0; 139 if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) { 140 uint64_t sp = regs_[ARM_REG_SP]; 141 // non-RT sigreturn call. 142 // __restore: 143 // 144 // Form 1 (arm): 145 // 0x77 0x70 mov r7, #0x77 146 // 0xa0 0xe3 svc 0x00000000 147 // 148 // Form 2 (arm): 149 // 0x77 0x00 0x90 0xef svc 0x00900077 150 // 151 // Form 3 (thumb): 152 // 0x77 0x27 movs r7, #77 153 // 0x00 0xdf svc 0 154 if (!process_memory->ReadFully(sp, &data, sizeof(data))) { 155 return false; 156 } 157 if (data == 0x5ac3c35a) { 158 // SP + uc_mcontext offset + r0 offset. 159 offset = sp + 0x14 + 0xc; 160 } else { 161 // SP + r0 offset 162 offset = sp + 0xc; 163 } 164 } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) { 165 uint64_t sp = regs_[ARM_REG_SP]; 166 // RT sigreturn call. 167 // __restore_rt: 168 // 169 // Form 1 (arm): 170 // 0xad 0x70 mov r7, #0xad 171 // 0xa0 0xe3 svc 0x00000000 172 // 173 // Form 2 (arm): 174 // 0xad 0x00 0x90 0xef svc 0x009000ad 175 // 176 // Form 3 (thumb): 177 // 0xad 0x27 movs r7, #ad 178 // 0x00 0xdf svc 0 179 if (!process_memory->ReadFully(sp, &data, sizeof(data))) { 180 return false; 181 } 182 if (data == sp + 8) { 183 // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset 184 offset = sp + 8 + 0x80 + 0x14 + 0xc; 185 } else { 186 // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset 187 offset = sp + 0x80 + 0x14 + 0xc; 188 } 189 } 190 if (offset == 0) { 191 return false; 192 } 193 194 if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) { 195 return false; 196 } 197 return true; 198} 199 200Regs* RegsArm::Clone() { 201 return new RegsArm(*this); 202} 203 204} // namespace unwindstack 205