brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.4 KiB · 45b6c8f Raw
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(), &regset,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 &reg_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 &reg_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