Coverage Report

Created: 2025-06-13 06:34

/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