377 lines · cpp
1//===-- NativeRegisterContextLinux_riscv64.cpp ----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#if defined(__riscv) && __riscv_xlen == 6410 11#include "NativeRegisterContextLinux_riscv64.h"12 13#include "lldb/Host/HostInfo.h"14#include "lldb/Utility/DataBufferHeap.h"15#include "lldb/Utility/Log.h"16#include "lldb/Utility/RegisterValue.h"17#include "lldb/Utility/Status.h"18 19#include "Plugins/Process/Linux/NativeProcessLinux.h"20#include "Plugins/Process/Linux/Procfs.h"21#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h"22#include "Plugins/Process/Utility/lldb-riscv-register-enums.h"23 24// System includes - They have to be included after framework includes because25// they define some macros which collide with variable names in other modules26#include <sys/ptrace.h>27#include <sys/uio.h>28// NT_PRSTATUS and NT_FPREGSET definition29#include <elf.h>30 31using namespace lldb;32using namespace lldb_private;33using namespace lldb_private::process_linux;34 35std::unique_ptr<NativeRegisterContextLinux>36NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(37 const ArchSpec &target_arch, NativeThreadLinux &native_thread) {38 switch (target_arch.GetMachine()) {39 case llvm::Triple::riscv64: {40 Flags opt_regsets(RegisterInfoPOSIX_riscv64::eRegsetMaskDefault);41 42 RegisterInfoPOSIX_riscv64::FPR fpr;43 struct iovec ioVec;44 ioVec.iov_base = &fpr;45 ioVec.iov_len = sizeof(fpr);46 unsigned int regset = NT_FPREGSET;47 48 if (NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET,49 native_thread.GetID(), ®set,50 &ioVec, sizeof(fpr))51 .Success()) {52 opt_regsets.Set(RegisterInfoPOSIX_riscv64::eRegsetMaskFP);53 }54 55 auto register_info_up =56 std::make_unique<RegisterInfoPOSIX_riscv64>(target_arch, opt_regsets);57 return std::make_unique<NativeRegisterContextLinux_riscv64>(58 target_arch, native_thread, std::move(register_info_up));59 }60 default:61 llvm_unreachable("have no register context for architecture");62 }63}64 65llvm::Expected<ArchSpec>66NativeRegisterContextLinux::DetermineArchitecture(lldb::tid_t tid) {67 return HostInfo::GetArchitecture();68}69 70NativeRegisterContextLinux_riscv64::NativeRegisterContextLinux_riscv64(71 const ArchSpec &target_arch, NativeThreadProtocol &native_thread,72 std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info_up)73 : NativeRegisterContextRegisterInfo(native_thread,74 register_info_up.release()),75 NativeRegisterContextLinux(native_thread) {76 ::memset(&m_fpr, 0, sizeof(m_fpr));77 ::memset(&m_gpr, 0, sizeof(m_gpr));78 79 m_gpr_is_valid = false;80 m_fpu_is_valid = false;81}82 83const RegisterInfoPOSIX_riscv64 &84NativeRegisterContextLinux_riscv64::GetRegisterInfo() const {85 return static_cast<const RegisterInfoPOSIX_riscv64 &>(86 NativeRegisterContextRegisterInfo::GetRegisterInfoInterface());87}88 89uint32_t NativeRegisterContextLinux_riscv64::GetRegisterSetCount() const {90 return GetRegisterInfo().GetRegisterSetCount();91}92 93const RegisterSet *94NativeRegisterContextLinux_riscv64::GetRegisterSet(uint32_t set_index) const {95 return GetRegisterInfo().GetRegisterSet(set_index);96}97 98uint32_t NativeRegisterContextLinux_riscv64::GetUserRegisterCount() const {99 uint32_t count = 0;100 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)101 count += GetRegisterSet(set_index)->num_registers;102 return count;103}104 105Status106NativeRegisterContextLinux_riscv64::ReadRegister(const RegisterInfo *reg_info,107 RegisterValue ®_value) {108 Status error;109 110 if (!reg_info) {111 error = Status::FromErrorString("reg_info NULL");112 return error;113 }114 115 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];116 117 if (reg == LLDB_INVALID_REGNUM)118 return Status::FromErrorStringWithFormat(119 "no lldb regnum for %s",120 reg_info && reg_info->name ? reg_info->name : "<unknown register>");121 122 if (reg == gpr_x0_riscv) {123 reg_value.SetUInt(0, reg_info->byte_size);124 return error;125 }126 127 uint8_t *src = nullptr;128 uint32_t offset = LLDB_INVALID_INDEX32;129 130 if (IsGPR(reg)) {131 error = ReadGPR();132 if (error.Fail())133 return error;134 135 offset = reg_info->byte_offset;136 assert(offset < GetGPRSize());137 src = (uint8_t *)GetGPRBuffer() + offset;138 139 } else if (IsFPR(reg)) {140 error = ReadFPR();141 if (error.Fail())142 return error;143 144 offset = CalculateFprOffset(reg_info);145 assert(offset < GetFPRSize());146 src = (uint8_t *)GetFPRBuffer() + offset;147 } else148 return Status::FromErrorString(149 "failed - register wasn't recognized to be a GPR or an FPR, "150 "write strategy unknown");151 152 reg_value.SetFromMemoryData(*reg_info, src, reg_info->byte_size,153 eByteOrderLittle, error);154 155 return error;156}157 158Status NativeRegisterContextLinux_riscv64::WriteRegister(159 const RegisterInfo *reg_info, const RegisterValue ®_value) {160 Status error;161 162 if (!reg_info)163 return Status::FromErrorString("reg_info NULL");164 165 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];166 167 if (reg == LLDB_INVALID_REGNUM)168 return Status::FromErrorStringWithFormat(169 "no lldb regnum for %s",170 reg_info->name != nullptr ? reg_info->name : "<unknown register>");171 172 if (reg == gpr_x0_riscv) {173 // do nothing.174 return error;175 }176 177 uint8_t *dst = nullptr;178 uint32_t offset = LLDB_INVALID_INDEX32;179 180 if (IsGPR(reg)) {181 error = ReadGPR();182 if (error.Fail())183 return error;184 185 assert(reg_info->byte_offset < GetGPRSize());186 dst = (uint8_t *)GetGPRBuffer() + reg_info->byte_offset;187 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);188 189 return WriteGPR();190 } else if (IsFPR(reg)) {191 error = ReadFPR();192 if (error.Fail())193 return error;194 195 offset = CalculateFprOffset(reg_info);196 assert(offset < GetFPRSize());197 dst = (uint8_t *)GetFPRBuffer() + offset;198 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);199 200 return WriteFPR();201 }202 203 return Status::FromErrorString("Failed to write register value");204}205 206Status NativeRegisterContextLinux_riscv64::ReadAllRegisterValues(207 lldb::WritableDataBufferSP &data_sp) {208 Status error;209 210 data_sp.reset(new DataBufferHeap(GetRegContextSize(), 0));211 212 error = ReadGPR();213 if (error.Fail())214 return error;215 216 if (GetRegisterInfo().IsFPPresent()) {217 error = ReadFPR();218 if (error.Fail())219 return error;220 }221 222 uint8_t *dst = const_cast<uint8_t *>(data_sp->GetBytes());223 ::memcpy(dst, GetGPRBuffer(), GetGPRSize());224 dst += GetGPRSize();225 if (GetRegisterInfo().IsFPPresent())226 ::memcpy(dst, GetFPRBuffer(), GetFPRSize());227 228 return error;229}230 231Status NativeRegisterContextLinux_riscv64::WriteAllRegisterValues(232 const lldb::DataBufferSP &data_sp) {233 Status error;234 235 if (!data_sp) {236 error = Status::FromErrorStringWithFormat(237 "NativeRegisterContextLinux_riscv64::%s invalid data_sp provided",238 __FUNCTION__);239 return error;240 }241 242 if (data_sp->GetByteSize() != GetRegContextSize()) {243 error = Status::FromErrorStringWithFormat(244 "NativeRegisterContextLinux_riscv64::%s data_sp contained mismatched "245 "data size, expected %" PRIu64 ", actual %" PRIu64,246 __FUNCTION__, GetRegContextSize(), data_sp->GetByteSize());247 return error;248 }249 250 uint8_t *src = const_cast<uint8_t *>(data_sp->GetBytes());251 if (src == nullptr) {252 error = Status::FromErrorStringWithFormat(253 "NativeRegisterContextLinux_riscv64::%s "254 "DataBuffer::GetBytes() returned a null "255 "pointer",256 __FUNCTION__);257 return error;258 }259 ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize());260 261 error = WriteGPR();262 if (error.Fail())263 return error;264 265 src += GetRegisterInfoInterface().GetGPRSize();266 267 if (GetRegisterInfo().IsFPPresent()) {268 ::memcpy(GetFPRBuffer(), src, GetFPRSize());269 270 error = WriteFPR();271 if (error.Fail())272 return error;273 }274 275 return error;276}277 278size_t NativeRegisterContextLinux_riscv64::GetRegContextSize() {279 size_t size = GetGPRSize();280 if (GetRegisterInfo().IsFPPresent())281 size += GetFPRSize();282 return size;283}284 285bool NativeRegisterContextLinux_riscv64::IsGPR(unsigned reg) const {286 return GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==287 RegisterInfoPOSIX_riscv64::GPRegSet;288}289 290bool NativeRegisterContextLinux_riscv64::IsFPR(unsigned reg) const {291 return GetRegisterInfo().IsFPReg(reg);292}293 294Status NativeRegisterContextLinux_riscv64::ReadGPR() {295 Status error;296 297 if (m_gpr_is_valid)298 return error;299 300 struct iovec ioVec;301 ioVec.iov_base = GetGPRBuffer();302 ioVec.iov_len = GetGPRSize();303 304 error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);305 306 if (error.Success())307 m_gpr_is_valid = true;308 309 return error;310}311 312Status NativeRegisterContextLinux_riscv64::WriteGPR() {313 Status error = ReadGPR();314 if (error.Fail())315 return error;316 317 struct iovec ioVec;318 ioVec.iov_base = GetGPRBuffer();319 ioVec.iov_len = GetGPRSize();320 321 m_gpr_is_valid = false;322 323 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);324}325 326Status NativeRegisterContextLinux_riscv64::ReadFPR() {327 Status error;328 329 if (m_fpu_is_valid)330 return error;331 332 struct iovec ioVec;333 ioVec.iov_base = GetFPRBuffer();334 ioVec.iov_len = GetFPRSize();335 336 error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);337 338 if (error.Success())339 m_fpu_is_valid = true;340 341 return error;342}343 344Status NativeRegisterContextLinux_riscv64::WriteFPR() {345 Status error = ReadFPR();346 if (error.Fail())347 return error;348 349 struct iovec ioVec;350 ioVec.iov_base = GetFPRBuffer();351 ioVec.iov_len = GetFPRSize();352 353 m_fpu_is_valid = false;354 355 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);356}357 358void NativeRegisterContextLinux_riscv64::InvalidateAllRegisters() {359 m_gpr_is_valid = false;360 m_fpu_is_valid = false;361}362 363uint32_t NativeRegisterContextLinux_riscv64::CalculateFprOffset(364 const RegisterInfo *reg_info) const {365 return reg_info->byte_offset - GetGPRSize();366}367 368std::vector<uint32_t> NativeRegisterContextLinux_riscv64::GetExpeditedRegisters(369 ExpeditedRegs expType) const {370 std::vector<uint32_t> expedited_reg_nums =371 NativeRegisterContext::GetExpeditedRegisters(expType);372 373 return expedited_reg_nums;374}375 376#endif // defined (__riscv) && __riscv_xlen == 64377