blob: b496187cb16e2bbd9cd7b219ca9215e327d84686 [file] [log] [blame]
Christopher Ferrisd06001d2017-11-30 18:56:01 -08001/*
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>
Florian Mayer3f1f2e02018-10-23 15:56:28 +010018#include <string.h>
Christopher Ferrisd06001d2017-11-30 18:56:01 -080019
20#include <functional>
21
22#include <unwindstack/Elf.h>
Christopher Ferris53914162018-02-08 19:27:47 -080023#include <unwindstack/MachineArm64.h>
Christopher Ferrisd06001d2017-11-30 18:56:01 -080024#include <unwindstack/MapInfo.h>
25#include <unwindstack/Memory.h>
26#include <unwindstack/RegsArm64.h>
Christopher Ferris53914162018-02-08 19:27:47 -080027#include <unwindstack/UcontextArm64.h>
28#include <unwindstack/UserArm64.h>
Christopher Ferrisd06001d2017-11-30 18:56:01 -080029
30namespace unwindstack {
31
32RegsArm64::RegsArm64()
Tamas Petz6835d012020-01-22 14:22:41 +010033 : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {
34 ResetPseudoRegisters();
35 pac_mask_ = 0;
36}
Christopher Ferrisd06001d2017-11-30 18:56:01 -080037
38ArchEnum RegsArm64::Arch() {
39 return ARCH_ARM64;
40}
41
Yabin Cui11e96fe2018-03-14 18:16:22 -070042uint64_t RegsArm64::pc() {
43 return regs_[ARM64_REG_PC];
44}
45
46uint64_t RegsArm64::sp() {
47 return regs_[ARM64_REG_SP];
48}
49
50void RegsArm64::set_pc(uint64_t pc) {
Tamas Petz6835d012020-01-22 14:22:41 +010051 // If the target is aarch64 then the return address may have been
52 // signed using the Armv8.3-A Pointer Authentication extension. The
53 // original return address can be restored by stripping out the
54 // authentication code using a mask or xpaclri. xpaclri is a NOP on
55 // pre-Armv8.3-A architectures.
56 if ((0 != pc) && IsRASigned()) {
57 if (pac_mask_) {
58 pc &= ~pac_mask_;
59#if defined(__aarch64__)
60 } else {
61 register uint64_t x30 __asm("x30") = pc;
62 // This is XPACLRI.
63 asm("hint 0x7" : "+r"(x30));
64 pc = x30;
65#endif
66 }
67 }
Yabin Cui11e96fe2018-03-14 18:16:22 -070068 regs_[ARM64_REG_PC] = pc;
69}
70
71void RegsArm64::set_sp(uint64_t sp) {
72 regs_[ARM64_REG_SP] = sp;
73}
74
Christopher Ferrisd06001d2017-11-30 18:56:01 -080075bool RegsArm64::SetPcFromReturnAddress(Memory*) {
Yabin Cui11e96fe2018-03-14 18:16:22 -070076 uint64_t lr = regs_[ARM64_REG_LR];
77 if (regs_[ARM64_REG_PC] == lr) {
Christopher Ferrisd06001d2017-11-30 18:56:01 -080078 return false;
79 }
80
Yabin Cui11e96fe2018-03-14 18:16:22 -070081 regs_[ARM64_REG_PC] = lr;
Christopher Ferrisd06001d2017-11-30 18:56:01 -080082 return true;
83}
84
85void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
86 fn("x0", regs_[ARM64_REG_R0]);
87 fn("x1", regs_[ARM64_REG_R1]);
88 fn("x2", regs_[ARM64_REG_R2]);
89 fn("x3", regs_[ARM64_REG_R3]);
90 fn("x4", regs_[ARM64_REG_R4]);
91 fn("x5", regs_[ARM64_REG_R5]);
92 fn("x6", regs_[ARM64_REG_R6]);
93 fn("x7", regs_[ARM64_REG_R7]);
94 fn("x8", regs_[ARM64_REG_R8]);
95 fn("x9", regs_[ARM64_REG_R9]);
96 fn("x10", regs_[ARM64_REG_R10]);
97 fn("x11", regs_[ARM64_REG_R11]);
98 fn("x12", regs_[ARM64_REG_R12]);
99 fn("x13", regs_[ARM64_REG_R13]);
100 fn("x14", regs_[ARM64_REG_R14]);
101 fn("x15", regs_[ARM64_REG_R15]);
102 fn("x16", regs_[ARM64_REG_R16]);
103 fn("x17", regs_[ARM64_REG_R17]);
104 fn("x18", regs_[ARM64_REG_R18]);
105 fn("x19", regs_[ARM64_REG_R19]);
106 fn("x20", regs_[ARM64_REG_R20]);
107 fn("x21", regs_[ARM64_REG_R21]);
108 fn("x22", regs_[ARM64_REG_R22]);
109 fn("x23", regs_[ARM64_REG_R23]);
110 fn("x24", regs_[ARM64_REG_R24]);
111 fn("x25", regs_[ARM64_REG_R25]);
112 fn("x26", regs_[ARM64_REG_R26]);
113 fn("x27", regs_[ARM64_REG_R27]);
114 fn("x28", regs_[ARM64_REG_R28]);
115 fn("x29", regs_[ARM64_REG_R29]);
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800116 fn("lr", regs_[ARM64_REG_LR]);
Ryan Savitski92237ba2020-01-24 19:34:13 +0000117 fn("sp", regs_[ARM64_REG_SP]);
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800118 fn("pc", regs_[ARM64_REG_PC]);
Peter Collingbournebb2f9412019-11-18 12:36:50 -0800119 fn("pst", regs_[ARM64_REG_PSTATE]);
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800120}
121
122Regs* RegsArm64::Read(void* remote_data) {
123 arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
124
125 RegsArm64* regs = new RegsArm64();
Ryan Savitski92237ba2020-01-24 19:34:13 +0000126 memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R30 + 1) * sizeof(uint64_t));
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800127 uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800128 reg_data[ARM64_REG_SP] = user->sp;
Ryan Savitski92237ba2020-01-24 19:34:13 +0000129 reg_data[ARM64_REG_PC] = user->pc;
Peter Collingbournebb2f9412019-11-18 12:36:50 -0800130 reg_data[ARM64_REG_PSTATE] = user->pstate;
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800131 return regs;
132}
133
134Regs* RegsArm64::CreateFromUcontext(void* ucontext) {
135 arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
136
137 RegsArm64* regs = new RegsArm64();
138 memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800139 return regs;
140}
141
Christopher Ferrisf0c82e72019-12-04 13:37:11 -0800142bool RegsArm64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800143 uint64_t data;
144 Memory* elf_memory = elf->memory();
145 // Read from elf memory since it is usually more expensive to read from
146 // process memory.
Christopher Ferrisf0c82e72019-12-04 13:37:11 -0800147 if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800148 return false;
149 }
150
151 // Look for the kernel sigreturn function.
152 // __kernel_rt_sigreturn:
153 // 0xd2801168 mov x8, #0x8b
154 // 0xd4000001 svc #0x0
155 if (data != 0xd4000001d2801168ULL) {
156 return false;
157 }
158
159 // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
Yabin Cui11e96fe2018-03-14 18:16:22 -0700160 if (!process_memory->ReadFully(regs_[ARM64_REG_SP] + 0x80 + 0xb0 + 0x08, regs_.data(),
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800161 sizeof(uint64_t) * ARM64_REG_LAST)) {
162 return false;
163 }
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800164 return true;
165}
166
Tamas Petz6835d012020-01-22 14:22:41 +0100167void RegsArm64::ResetPseudoRegisters(void) {
168 // DWARF for AArch64 says RA_SIGN_STATE should be initialized to 0.
169 this->SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 0);
170}
171
172bool RegsArm64::SetPseudoRegister(uint16_t id, uint64_t value) {
173 if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) {
174 pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST] = value;
175 return true;
176 }
177 return false;
178}
179
180bool RegsArm64::GetPseudoRegister(uint16_t id, uint64_t* value) {
181 if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) {
182 *value = pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST];
183 return true;
184 }
185 return false;
186}
187
188bool RegsArm64::IsRASigned() {
189 uint64_t value;
190 auto result = this->GetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, &value);
191 return (result && (value != 0));
192}
193
194void RegsArm64::SetPACMask(uint64_t mask) {
195 pac_mask_ = mask;
196}
197
Josh Gao2f37a152018-04-20 11:51:14 -0700198Regs* RegsArm64::Clone() {
199 return new RegsArm64(*this);
200}
201
Christopher Ferrisd06001d2017-11-30 18:56:01 -0800202} // namespace unwindstack