/src/perfetto/buildtools/android-unwinding/libunwindstack/RegsArm64.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include <string.h> |
19 | | |
20 | | #include <functional> |
21 | | |
22 | | #if defined(__BIONIC__) |
23 | | #include <bionic/pac.h> |
24 | | #endif |
25 | | |
26 | | #include <unwindstack/Elf.h> |
27 | | #include <unwindstack/MachineArm64.h> |
28 | | #include <unwindstack/MapInfo.h> |
29 | | #include <unwindstack/Memory.h> |
30 | | #include <unwindstack/RegsArm64.h> |
31 | | #include <unwindstack/UcontextArm64.h> |
32 | | #include <unwindstack/UserArm64.h> |
33 | | |
34 | | namespace unwindstack { |
35 | | |
36 | | RegsArm64::RegsArm64() |
37 | 2.13k | : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) { |
38 | 2.13k | ResetPseudoRegisters(); |
39 | 2.13k | pac_mask_ = 0; |
40 | 2.13k | } |
41 | | |
42 | 5.95k | ArchEnum RegsArm64::Arch() { |
43 | 5.95k | return ARCH_ARM64; |
44 | 5.95k | } |
45 | | |
46 | 42.6k | uint64_t RegsArm64::pc() { |
47 | 42.6k | return regs_[ARM64_REG_PC]; |
48 | 42.6k | } |
49 | | |
50 | 20.3k | uint64_t RegsArm64::sp() { |
51 | 20.3k | return regs_[ARM64_REG_SP]; |
52 | 20.3k | } |
53 | | |
54 | 696 | static uint64_t strip_pac(uint64_t pc, uint64_t mask) { |
55 | | // If the target is aarch64 then the return address may have been |
56 | | // signed using the Armv8.3-A Pointer Authentication extension. The |
57 | | // original return address can be restored by stripping out the |
58 | | // authentication code using a mask or xpaclri. xpaclri is a NOP on |
59 | | // pre-Armv8.3-A architectures. |
60 | 696 | if (mask) { |
61 | 0 | pc &= ~mask; |
62 | 696 | } else { |
63 | | #if defined(__BIONIC__) |
64 | | pc = __bionic_clear_pac_bits(pc); |
65 | | #endif |
66 | 696 | } |
67 | 696 | return pc; |
68 | 696 | } |
69 | | |
70 | 1.22k | void RegsArm64::set_pc(uint64_t pc) { |
71 | 1.22k | if ((0 != pc) && IsRASigned()) { |
72 | 250 | pc = strip_pac(pc, pac_mask_); |
73 | 250 | } |
74 | 1.22k | regs_[ARM64_REG_PC] = pc; |
75 | 1.22k | } |
76 | | |
77 | 1.22k | void RegsArm64::set_sp(uint64_t sp) { |
78 | 1.22k | regs_[ARM64_REG_SP] = sp; |
79 | 1.22k | } |
80 | | |
81 | 446 | void RegsArm64::fallback_pc() { |
82 | | // As a last resort, try stripping the PC of the pointer |
83 | | // authentication code. |
84 | 446 | regs_[ARM64_REG_PC] = strip_pac(regs_[ARM64_REG_PC], pac_mask_); |
85 | 446 | } |
86 | | |
87 | 4.02k | bool RegsArm64::SetPcFromReturnAddress(Memory*) { |
88 | 4.02k | uint64_t lr = regs_[ARM64_REG_LR]; |
89 | 4.02k | if (regs_[ARM64_REG_PC] == lr) { |
90 | 0 | return false; |
91 | 0 | } |
92 | | |
93 | 4.02k | regs_[ARM64_REG_PC] = lr; |
94 | 4.02k | return true; |
95 | 4.02k | } |
96 | | |
97 | 0 | void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) { |
98 | 0 | fn("x0", regs_[ARM64_REG_R0]); |
99 | 0 | fn("x1", regs_[ARM64_REG_R1]); |
100 | 0 | fn("x2", regs_[ARM64_REG_R2]); |
101 | 0 | fn("x3", regs_[ARM64_REG_R3]); |
102 | 0 | fn("x4", regs_[ARM64_REG_R4]); |
103 | 0 | fn("x5", regs_[ARM64_REG_R5]); |
104 | 0 | fn("x6", regs_[ARM64_REG_R6]); |
105 | 0 | fn("x7", regs_[ARM64_REG_R7]); |
106 | 0 | fn("x8", regs_[ARM64_REG_R8]); |
107 | 0 | fn("x9", regs_[ARM64_REG_R9]); |
108 | 0 | fn("x10", regs_[ARM64_REG_R10]); |
109 | 0 | fn("x11", regs_[ARM64_REG_R11]); |
110 | 0 | fn("x12", regs_[ARM64_REG_R12]); |
111 | 0 | fn("x13", regs_[ARM64_REG_R13]); |
112 | 0 | fn("x14", regs_[ARM64_REG_R14]); |
113 | 0 | fn("x15", regs_[ARM64_REG_R15]); |
114 | 0 | fn("x16", regs_[ARM64_REG_R16]); |
115 | 0 | fn("x17", regs_[ARM64_REG_R17]); |
116 | 0 | fn("x18", regs_[ARM64_REG_R18]); |
117 | 0 | fn("x19", regs_[ARM64_REG_R19]); |
118 | 0 | fn("x20", regs_[ARM64_REG_R20]); |
119 | 0 | fn("x21", regs_[ARM64_REG_R21]); |
120 | 0 | fn("x22", regs_[ARM64_REG_R22]); |
121 | 0 | fn("x23", regs_[ARM64_REG_R23]); |
122 | 0 | fn("x24", regs_[ARM64_REG_R24]); |
123 | 0 | fn("x25", regs_[ARM64_REG_R25]); |
124 | 0 | fn("x26", regs_[ARM64_REG_R26]); |
125 | 0 | fn("x27", regs_[ARM64_REG_R27]); |
126 | 0 | fn("x28", regs_[ARM64_REG_R28]); |
127 | 0 | fn("x29", regs_[ARM64_REG_R29]); |
128 | 0 | fn("lr", regs_[ARM64_REG_LR]); |
129 | 0 | fn("sp", regs_[ARM64_REG_SP]); |
130 | 0 | fn("pc", regs_[ARM64_REG_PC]); |
131 | 0 | fn("pst", regs_[ARM64_REG_PSTATE]); |
132 | 0 | } |
133 | | |
134 | 0 | Regs* RegsArm64::Read(const void* remote_data) { |
135 | 0 | const arm64_user_regs* user = reinterpret_cast<const arm64_user_regs*>(remote_data); |
136 | |
|
137 | 0 | RegsArm64* regs = new RegsArm64(); |
138 | 0 | memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R30 + 1) * sizeof(uint64_t)); |
139 | 0 | uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData()); |
140 | 0 | reg_data[ARM64_REG_SP] = user->sp; |
141 | 0 | reg_data[ARM64_REG_PC] = user->pc; |
142 | 0 | reg_data[ARM64_REG_PSTATE] = user->pstate; |
143 | 0 | return regs; |
144 | 0 | } |
145 | | |
146 | 0 | Regs* RegsArm64::CreateFromUcontext(void* ucontext) { |
147 | 0 | arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext); |
148 | |
|
149 | 0 | RegsArm64* regs = new RegsArm64(); |
150 | 0 | memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t)); |
151 | 0 | return regs; |
152 | 0 | } |
153 | | |
154 | 3.54k | bool RegsArm64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) { |
155 | | // Read from elf memory since it is usually more expensive to read from |
156 | | // process memory. |
157 | 3.54k | uint64_t data; |
158 | 3.54k | if (!elf->memory()->ReadFully(elf_offset, &data, sizeof(data))) { |
159 | 1.97k | return false; |
160 | 1.97k | } |
161 | | |
162 | | // Look for the kernel sigreturn function. |
163 | | // __kernel_rt_sigreturn: |
164 | | // 0xd2801168 mov x8, #0x8b |
165 | | // 0xd4000001 svc #0x0 |
166 | 1.57k | if (data != 0xd4000001d2801168ULL) { |
167 | 1.57k | return false; |
168 | 1.57k | } |
169 | | |
170 | | // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset. |
171 | 2 | if (!process_memory->ReadFully(regs_[ARM64_REG_SP] + 0x80 + 0xb0 + 0x08, regs_.data(), |
172 | 2 | sizeof(uint64_t) * ARM64_REG_LAST)) { |
173 | 2 | return false; |
174 | 2 | } |
175 | 0 | return true; |
176 | 2 | } |
177 | | |
178 | 3.59k | void RegsArm64::ResetPseudoRegisters(void) { |
179 | | // DWARF for AArch64 says RA_SIGN_STATE should be initialized to 0. |
180 | 3.59k | this->SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 0); |
181 | 3.59k | } |
182 | | |
183 | 3.84k | bool RegsArm64::SetPseudoRegister(uint16_t id, uint64_t value) { |
184 | 3.84k | if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { |
185 | 3.84k | pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST] = value; |
186 | 3.84k | return true; |
187 | 3.84k | } |
188 | 0 | return false; |
189 | 3.84k | } |
190 | | |
191 | 1.22k | bool RegsArm64::GetPseudoRegister(uint16_t id, uint64_t* value) { |
192 | 1.22k | if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { |
193 | 1.22k | *value = pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST]; |
194 | 1.22k | return true; |
195 | 1.22k | } |
196 | 0 | return false; |
197 | 1.22k | } |
198 | | |
199 | 1.22k | bool RegsArm64::IsRASigned() { |
200 | 1.22k | uint64_t value; |
201 | 1.22k | auto result = this->GetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, &value); |
202 | 1.22k | return (result && (value != 0)); |
203 | 1.22k | } |
204 | | |
205 | 0 | void RegsArm64::SetPACMask(uint64_t mask) { |
206 | 0 | pac_mask_ = mask; |
207 | 0 | } |
208 | | |
209 | 0 | Regs* RegsArm64::Clone() { |
210 | 0 | return new RegsArm64(*this); |
211 | 0 | } |
212 | | |
213 | | } // namespace unwindstack |