Coverage Report

Created: 2025-06-13 06:34

/src/perfetto/buildtools/android-unwinding/libunwindstack/RegsRiscv64.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2022 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
#include <string.h>
20
#include <sys/ptrace.h>
21
#include <sys/uio.h>
22
23
#include <functional>
24
#include <vector>
25
26
#include <unwindstack/Elf.h>
27
#include <unwindstack/MachineRiscv64.h>
28
#include <unwindstack/MapInfo.h>
29
#include <unwindstack/Memory.h>
30
#include <unwindstack/RegsRiscv64.h>
31
#include <unwindstack/UcontextRiscv64.h>
32
#include <unwindstack/UserRiscv64.h>
33
34
namespace unwindstack {
35
36
0
uint64_t RegsRiscv64::GetVlenbFromLocal() {
37
#if defined(__riscv)
38
  // Assumes that all cpus have the same value.
39
  uint64_t vlenb;
40
  asm volatile("csrr %0, 0xc22\n" : "=r"(vlenb)::);
41
  return vlenb;
42
#else
43
0
  return 0;
44
0
#endif
45
0
}
46
47
0
uint64_t RegsRiscv64::GetVlenbFromRemote(pid_t pid) {
48
0
  if (pid == 0) {
49
0
    return GetVlenbFromLocal();
50
0
  }
51
52
  // We only care about these values, no need to get the other vector registers.
53
0
  struct riscv64_v_regset_state regs;
54
0
  struct iovec io = {.iov_base = &regs, .iov_len = sizeof(regs)};
55
0
  if (ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, reinterpret_cast<void*>(&io)) == -1) {
56
    // TODO: Workaround due to some devices not properly returning these values.
57
    // This code assumes that all cores on the device have the same vlenb.
58
0
    return GetVlenbFromLocal();
59
0
  }
60
0
  return regs.vlenb;
61
0
}
62
63
RegsRiscv64::RegsRiscv64()
64
0
    : RegsImpl<uint64_t>(RISCV64_REG_COUNT, Location(LOCATION_REGISTER, RISCV64_REG_RA)) {}
65
66
0
ArchEnum RegsRiscv64::Arch() {
67
0
  return ARCH_RISCV64;
68
0
}
69
70
0
uint64_t RegsRiscv64::pc() {
71
0
  return regs_[RISCV64_REG_PC];
72
0
}
73
74
0
uint64_t RegsRiscv64::sp() {
75
0
  return regs_[RISCV64_REG_SP];
76
0
}
77
78
0
void RegsRiscv64::set_pc(uint64_t pc) {
79
0
  regs_[RISCV64_REG_PC] = pc;
80
0
}
81
82
0
void RegsRiscv64::set_sp(uint64_t sp) {
83
0
  regs_[RISCV64_REG_SP] = sp;
84
0
}
85
86
0
bool RegsRiscv64::SetPcFromReturnAddress(Memory*) {
87
0
  uint64_t ra = regs_[RISCV64_REG_RA];
88
0
  if (regs_[RISCV64_REG_PC] == ra) {
89
0
    return false;
90
0
  }
91
92
0
  regs_[RISCV64_REG_PC] = ra;
93
0
  return true;
94
0
}
95
96
0
void RegsRiscv64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
97
0
  fn("pc", regs_[RISCV64_REG_PC]);
98
0
  fn("ra", regs_[RISCV64_REG_RA]);
99
0
  fn("sp", regs_[RISCV64_REG_SP]);
100
0
  fn("gp", regs_[RISCV64_REG_GP]);
101
0
  fn("tp", regs_[RISCV64_REG_TP]);
102
0
  fn("t0", regs_[RISCV64_REG_T0]);
103
0
  fn("t1", regs_[RISCV64_REG_T1]);
104
0
  fn("t2", regs_[RISCV64_REG_T2]);
105
0
  fn("t3", regs_[RISCV64_REG_T3]);
106
0
  fn("t4", regs_[RISCV64_REG_T4]);
107
0
  fn("t5", regs_[RISCV64_REG_T5]);
108
0
  fn("t6", regs_[RISCV64_REG_T6]);
109
0
  fn("s0", regs_[RISCV64_REG_S0]);
110
0
  fn("s1", regs_[RISCV64_REG_S1]);
111
0
  fn("s2", regs_[RISCV64_REG_S2]);
112
0
  fn("s3", regs_[RISCV64_REG_S3]);
113
0
  fn("s4", regs_[RISCV64_REG_S4]);
114
0
  fn("s5", regs_[RISCV64_REG_S5]);
115
0
  fn("s6", regs_[RISCV64_REG_S6]);
116
0
  fn("s7", regs_[RISCV64_REG_S7]);
117
0
  fn("s8", regs_[RISCV64_REG_S8]);
118
0
  fn("s9", regs_[RISCV64_REG_S9]);
119
0
  fn("s10", regs_[RISCV64_REG_S10]);
120
0
  fn("s11", regs_[RISCV64_REG_S11]);
121
0
  fn("a0", regs_[RISCV64_REG_A0]);
122
0
  fn("a1", regs_[RISCV64_REG_A1]);
123
0
  fn("a2", regs_[RISCV64_REG_A2]);
124
0
  fn("a3", regs_[RISCV64_REG_A3]);
125
0
  fn("a4", regs_[RISCV64_REG_A4]);
126
0
  fn("a5", regs_[RISCV64_REG_A5]);
127
0
  fn("a6", regs_[RISCV64_REG_A6]);
128
0
  fn("a7", regs_[RISCV64_REG_A7]);
129
0
  fn("vlenb", regs_[RISCV64_REG_VLENB]);
130
0
}
131
132
0
Regs* RegsRiscv64::Read(const void* remote_data, pid_t pid) {
133
0
  const riscv64_user_regs* user = reinterpret_cast<const riscv64_user_regs*>(remote_data);
134
135
0
  RegsRiscv64* regs = new RegsRiscv64();
136
0
  memcpy(regs->RawData(), &user->regs[0], RISCV64_REG_REAL_COUNT * sizeof(uint64_t));
137
0
  regs->regs_[RISCV64_REG_VLENB] = GetVlenbFromRemote(pid);
138
0
  return regs;
139
0
}
140
141
0
Regs* RegsRiscv64::CreateFromUcontext(void* ucontext) {
142
0
  riscv64_ucontext_t* riscv64_ucontext = reinterpret_cast<riscv64_ucontext_t*>(ucontext);
143
144
0
  RegsRiscv64* regs = new RegsRiscv64();
145
0
  memcpy(regs->RawData(), &riscv64_ucontext->uc_mcontext.__gregs[0],
146
0
         RISCV64_REG_REAL_COUNT * sizeof(uint64_t));
147
148
  // TODO: Until b/323045700 is fixed, this code temporarily assumes
149
  // this function will only be called on the same core an unwind occurs.
150
  // If not, the vlenb value might be wrong.
151
0
  uint64_t* raw_data = reinterpret_cast<uint64_t*>(regs->RawData());
152
0
  raw_data[RISCV64_REG_VLENB] = GetVlenbFromLocal();
153
0
  return regs;
154
0
}
155
156
0
bool RegsRiscv64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
157
  // Read from elf memory since it is usually more expensive to read from
158
  // process memory.
159
0
  uint64_t data;
160
0
  if (!elf->memory()->ReadFully(elf_offset, &data, sizeof(data))) {
161
0
    return false;
162
0
  }
163
  // Look for the kernel sigreturn function.
164
  // __kernel_rt_sigreturn:
165
  // li a7, __NR_rt_sigreturn
166
  // scall
167
168
0
  const uint8_t li_scall[] = {0x93, 0x08, 0xb0, 0x08, 0x73, 0x00, 0x00, 0x00};
169
0
  if (memcmp(&data, &li_scall, 8) != 0) {
170
0
    return false;
171
0
  }
172
173
  // SP + sizeof(siginfo_t) + uc_mcontext offset + PC offset.
174
0
  if (!process_memory->ReadFully(regs_[RISCV64_REG_SP] + 0x80 + 0xb0 + 0x00, regs_.data(),
175
0
                                 sizeof(uint64_t) * (RISCV64_REG_REAL_COUNT))) {
176
0
    return false;
177
0
  }
178
0
  return true;
179
0
}
180
181
0
Regs* RegsRiscv64::Clone() {
182
0
  return new RegsRiscv64(*this);
183
0
}
184
185
0
uint16_t RegsRiscv64::Convert(uint16_t reg) {
186
0
  if (reg == 0x1c22) {
187
0
    return RISCV64_REG_VLENB;
188
0
  }
189
0
  if (reg == RISCV64_REG_VLENB) {
190
    // It should never be valid for the register to be vlenb naturally.
191
0
    return total_regs();
192
0
  }
193
0
  return reg;
194
0
}
195
196
}  // namespace unwindstack