/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 = ®s, .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 |