149 lines
4.3 KiB
C++
149 lines
4.3 KiB
C++
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <functional>
|
|
|
|
#include <unwindstack/Elf.h>
|
|
#include <unwindstack/MachineRiscv64.h>
|
|
#include <unwindstack/MapInfo.h>
|
|
#include <unwindstack/Memory.h>
|
|
#include <unwindstack/RegsRiscv64.h>
|
|
#include <unwindstack/UcontextRiscv64.h>
|
|
#include <unwindstack/UserRiscv64.h>
|
|
|
|
namespace unwindstack {
|
|
|
|
RegsRiscv64::RegsRiscv64()
|
|
: RegsImpl<uint64_t>(RISCV64_REG_MAX, Location(LOCATION_REGISTER, RISCV64_REG_RA)) {}
|
|
|
|
ArchEnum RegsRiscv64::Arch() {
|
|
return ARCH_RISCV64;
|
|
}
|
|
|
|
uint64_t RegsRiscv64::pc() {
|
|
return regs_[RISCV64_REG_PC];
|
|
}
|
|
|
|
uint64_t RegsRiscv64::sp() {
|
|
return regs_[RISCV64_REG_SP];
|
|
}
|
|
|
|
void RegsRiscv64::set_pc(uint64_t pc) {
|
|
regs_[RISCV64_REG_PC] = pc;
|
|
}
|
|
|
|
void RegsRiscv64::set_sp(uint64_t sp) {
|
|
regs_[RISCV64_REG_SP] = sp;
|
|
}
|
|
|
|
bool RegsRiscv64::SetPcFromReturnAddress(Memory*) {
|
|
uint64_t ra = regs_[RISCV64_REG_RA];
|
|
if (regs_[RISCV64_REG_PC] == ra) {
|
|
return false;
|
|
}
|
|
|
|
regs_[RISCV64_REG_PC] = ra;
|
|
return true;
|
|
}
|
|
|
|
void RegsRiscv64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
|
|
fn("pc", regs_[RISCV64_REG_PC]);
|
|
fn("ra", regs_[RISCV64_REG_RA]);
|
|
fn("sp", regs_[RISCV64_REG_SP]);
|
|
fn("gp", regs_[RISCV64_REG_GP]);
|
|
fn("tp", regs_[RISCV64_REG_TP]);
|
|
fn("t0", regs_[RISCV64_REG_T0]);
|
|
fn("t1", regs_[RISCV64_REG_T1]);
|
|
fn("t2", regs_[RISCV64_REG_T2]);
|
|
fn("t3", regs_[RISCV64_REG_T3]);
|
|
fn("t4", regs_[RISCV64_REG_T4]);
|
|
fn("t5", regs_[RISCV64_REG_T5]);
|
|
fn("t6", regs_[RISCV64_REG_T6]);
|
|
fn("s0", regs_[RISCV64_REG_S0]);
|
|
fn("s1", regs_[RISCV64_REG_S1]);
|
|
fn("s2", regs_[RISCV64_REG_S2]);
|
|
fn("s3", regs_[RISCV64_REG_S3]);
|
|
fn("s4", regs_[RISCV64_REG_S4]);
|
|
fn("s5", regs_[RISCV64_REG_S5]);
|
|
fn("s6", regs_[RISCV64_REG_S6]);
|
|
fn("s7", regs_[RISCV64_REG_S7]);
|
|
fn("s8", regs_[RISCV64_REG_S8]);
|
|
fn("s9", regs_[RISCV64_REG_S9]);
|
|
fn("s10", regs_[RISCV64_REG_S10]);
|
|
fn("s11", regs_[RISCV64_REG_S11]);
|
|
fn("a0", regs_[RISCV64_REG_A0]);
|
|
fn("a1", regs_[RISCV64_REG_A1]);
|
|
fn("a2", regs_[RISCV64_REG_A2]);
|
|
fn("a3", regs_[RISCV64_REG_A3]);
|
|
fn("a4", regs_[RISCV64_REG_A4]);
|
|
fn("a5", regs_[RISCV64_REG_A5]);
|
|
fn("a6", regs_[RISCV64_REG_A6]);
|
|
fn("a7", regs_[RISCV64_REG_A7]);
|
|
}
|
|
|
|
Regs* RegsRiscv64::Read(void* remote_data) {
|
|
riscv64_user_regs* user = reinterpret_cast<riscv64_user_regs*>(remote_data);
|
|
|
|
RegsRiscv64* regs = new RegsRiscv64();
|
|
memcpy(regs->RawData(), &user->regs[0], RISCV64_REG_MAX * sizeof(uint64_t));
|
|
// uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
|
|
return regs;
|
|
}
|
|
|
|
Regs* RegsRiscv64::CreateFromUcontext(void* ucontext) {
|
|
riscv64_ucontext_t* riscv64_ucontext = reinterpret_cast<riscv64_ucontext_t*>(ucontext);
|
|
|
|
RegsRiscv64* regs = new RegsRiscv64();
|
|
memcpy(regs->RawData(), &riscv64_ucontext->uc_mcontext.__gregs[0],
|
|
RISCV64_REG_MAX * sizeof(uint64_t));
|
|
return regs;
|
|
}
|
|
|
|
bool RegsRiscv64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
|
|
uint64_t data;
|
|
Memory* elf_memory = elf->memory();
|
|
// Read from elf memory since it is usually more expensive to read from
|
|
// process memory.
|
|
if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
|
|
return false;
|
|
}
|
|
// Look for the kernel sigreturn function.
|
|
// __kernel_rt_sigreturn:
|
|
// li a7, __NR_rt_sigreturn
|
|
// scall
|
|
|
|
const uint8_t li_scall[] = {0x93, 0x08, 0xb0, 0x08, 0x73, 0x00, 0x00, 0x00};
|
|
if (memcmp(&data, &li_scall, 8) != 0) {
|
|
return false;
|
|
}
|
|
|
|
// SP + sizeof(siginfo_t) + uc_mcontext offset + PC offset.
|
|
if (!process_memory->ReadFully(regs_[RISCV64_REG_SP] + 0x80 + 0xb0 + 0x00, regs_.data(),
|
|
sizeof(uint64_t) * (RISCV64_REG_MAX))) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Regs* RegsRiscv64::Clone() {
|
|
return new RegsRiscv64(*this);
|
|
}
|
|
|
|
} // namespace unwindstack
|