1210284Sjmallett//===-- NativeRegisterContextFreeBSD_mips64.cpp ---------------------------===//
2210284Sjmallett//
3210284Sjmallett// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4210284Sjmallett// See https://llvm.org/LICENSE.txt for license information.
5210284Sjmallett// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6210284Sjmallett//
7210284Sjmallett//===----------------------------------------------------------------------===//
8210284Sjmallett
9210284Sjmallett#if defined(__mips64__)
10210284Sjmallett
11210284Sjmallett#include "NativeRegisterContextFreeBSD_mips64.h"
12210284Sjmallett
13210284Sjmallett#include "lldb/Utility/DataBufferHeap.h"
14210284Sjmallett#include "lldb/Utility/RegisterValue.h"
15210284Sjmallett#include "lldb/Utility/Status.h"
16210284Sjmallett
17210284Sjmallett#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
18210284Sjmallett#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h"
19210284Sjmallett
20210284Sjmallett// clang-format off
21210284Sjmallett#include <sys/param.h>
22210284Sjmallett#include <sys/ptrace.h>
23210284Sjmallett#include <sys/types.h>
24210284Sjmallett// clang-format on
25210284Sjmallett#include <optional>
26210284Sjmallett
27210284Sjmallettusing namespace lldb;
28210284Sjmallettusing namespace lldb_private;
29210284Sjmallettusing namespace lldb_private::process_freebsd;
30210284Sjmallett
31210284SjmallettNativeRegisterContextFreeBSD *
32210284SjmallettNativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
33210284Sjmallett    const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
34210284Sjmallett  return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread);
35210284Sjmallett}
36210284Sjmallett
37210284SjmallettNativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64(
38210284Sjmallett    const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
39210284Sjmallett    : NativeRegisterContextRegisterInfo(
40210284Sjmallett          native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {}
41210284Sjmallett
42210284SjmallettRegisterContextFreeBSD_mips64 &
43210284SjmallettNativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const {
44210284Sjmallett  return static_cast<RegisterContextFreeBSD_mips64 &>(
45210284Sjmallett      *m_register_info_interface_up);
46210284Sjmallett}
47210284Sjmallett
48210284Sjmallettuint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const {
49210284Sjmallett  return GetRegisterInfo().GetRegisterSetCount();
50210284Sjmallett}
51210284Sjmallett
52210284Sjmallettconst RegisterSet *
53210284SjmallettNativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const {
54210284Sjmallett  return GetRegisterInfo().GetRegisterSet(set_index);
55210284Sjmallett}
56210284Sjmallett
57210284Sjmallettuint32_t NativeRegisterContextFreeBSD_mips64::GetUserRegisterCount() const {
58210284Sjmallett  uint32_t count = 0;
59210284Sjmallett  for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
60210284Sjmallett    count += GetRegisterSet(set_index)->num_registers;
61210284Sjmallett  return count;
62210284Sjmallett}
63210284Sjmallett
64210284Sjmallettstd::optional<NativeRegisterContextFreeBSD_mips64::RegSetKind>
65210284SjmallettNativeRegisterContextFreeBSD_mips64::GetSetForNativeRegNum(
66210284Sjmallett    uint32_t reg_num) const {
67210284Sjmallett  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
68210284Sjmallett  case llvm::Triple::mips64:
69210284Sjmallett    if (reg_num >= k_first_gpr_mips64 && reg_num <= k_last_gpr_mips64)
70210284Sjmallett      return GPRegSet;
71210284Sjmallett    if (reg_num >= k_first_fpr_mips64 && reg_num <= k_last_fpr_mips64)
72210284Sjmallett      return FPRegSet;
73210284Sjmallett    break;
74210284Sjmallett  default:
75210284Sjmallett    llvm_unreachable("Unhandled target architecture.");
76210284Sjmallett  }
77210284Sjmallett
78210284Sjmallett  llvm_unreachable("Register does not belong to any register set");
79210284Sjmallett}
80210284Sjmallett
81210284SjmallettStatus NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) {
82210284Sjmallett  switch (set) {
83210284Sjmallett  case GPRegSet:
84210284Sjmallett    return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
85210284Sjmallett                                               m_reg_data.data());
86210284Sjmallett  case FPRegSet:
87210284Sjmallett    return NativeProcessFreeBSD::PtraceWrapper(
88210284Sjmallett        PT_GETFPREGS, m_thread.GetID(),
89210284Sjmallett        m_reg_data.data() + GetRegisterInfo().GetGPRSize());
90210284Sjmallett  }
91210284Sjmallett  llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet");
92210284Sjmallett}
93210284Sjmallett
94210284SjmallettStatus NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) {
95210284Sjmallett  switch (set) {
96210284Sjmallett  case GPRegSet:
97210284Sjmallett    return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
98210284Sjmallett                                               m_reg_data.data());
99210284Sjmallett  case FPRegSet:
100210284Sjmallett    return NativeProcessFreeBSD::PtraceWrapper(
101210284Sjmallett        PT_SETFPREGS, m_thread.GetID(),
102210284Sjmallett        m_reg_data.data() + GetRegisterInfo().GetGPRSize());
103210284Sjmallett  }
104210284Sjmallett  llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet");
105210284Sjmallett}
106210284Sjmallett
107210284SjmallettStatus
108210284SjmallettNativeRegisterContextFreeBSD_mips64::ReadRegister(const RegisterInfo *reg_info,
109210284Sjmallett                                                  RegisterValue &reg_value) {
110210284Sjmallett  Status error;
111210284Sjmallett
112210284Sjmallett  if (!reg_info) {
113210284Sjmallett    error.SetErrorString("reg_info NULL");
114210284Sjmallett    return error;
115210284Sjmallett  }
116210284Sjmallett
117210284Sjmallett  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
118210284Sjmallett
119210284Sjmallett  if (reg == LLDB_INVALID_REGNUM)
120210284Sjmallett    return Status("no lldb regnum for %s", reg_info && reg_info->name
121210284Sjmallett                                               ? reg_info->name
122210284Sjmallett                                               : "<unknown register>");
123210284Sjmallett
124210284Sjmallett  std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
125210284Sjmallett  if (!opt_set) {
126210284Sjmallett    // This is likely an internal register for lldb use only and should not be
127210284Sjmallett    // directly queried.
128210284Sjmallett    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
129210284Sjmallett                                   reg_info->name);
130210284Sjmallett    return error;
131210284Sjmallett  }
132210284Sjmallett
133210284Sjmallett  RegSetKind set = *opt_set;
134210284Sjmallett  error = ReadRegisterSet(set);
135210284Sjmallett  if (error.Fail())
136210284Sjmallett    return error;
137210284Sjmallett
138210284Sjmallett  assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
139210284Sjmallett  reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
140210284Sjmallett                     reg_info->byte_size, endian::InlHostByteOrder());
141210284Sjmallett  return error;
142210284Sjmallett}
143210284Sjmallett
144210284SjmallettStatus NativeRegisterContextFreeBSD_mips64::WriteRegister(
145210284Sjmallett    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
146210284Sjmallett  Status error;
147210284Sjmallett
148210284Sjmallett  if (!reg_info)
149210284Sjmallett    return Status("reg_info NULL");
150210284Sjmallett
151210284Sjmallett  const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
152210284Sjmallett
153210284Sjmallett  if (reg == LLDB_INVALID_REGNUM)
154210284Sjmallett    return Status("no lldb regnum for %s", reg_info && reg_info->name
155210284Sjmallett                                               ? reg_info->name
156210284Sjmallett                                               : "<unknown register>");
157210284Sjmallett
158210284Sjmallett  std::optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
159210284Sjmallett  if (!opt_set) {
160210284Sjmallett    // This is likely an internal register for lldb use only and should not be
161210284Sjmallett    // directly queried.
162210284Sjmallett    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
163210284Sjmallett                                   reg_info->name);
164210284Sjmallett    return error;
165210284Sjmallett  }
166210284Sjmallett
167210284Sjmallett  RegSetKind set = *opt_set;
168210284Sjmallett  error = ReadRegisterSet(set);
169210284Sjmallett  if (error.Fail())
170210284Sjmallett    return error;
171210284Sjmallett
172210284Sjmallett  assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
173210284Sjmallett  ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
174210284Sjmallett           reg_info->byte_size);
175210284Sjmallett
176210284Sjmallett  return WriteRegisterSet(set);
177210284Sjmallett}
178210284Sjmallett
179210284SjmallettStatus NativeRegisterContextFreeBSD_mips64::ReadAllRegisterValues(
180210284Sjmallett    lldb::WritableDataBufferSP &data_sp) {
181210284Sjmallett  Status error;
182210284Sjmallett
183210284Sjmallett  error = ReadRegisterSet(GPRegSet);
184210284Sjmallett  if (error.Fail())
185210284Sjmallett    return error;
186210284Sjmallett
187210284Sjmallett  error = ReadRegisterSet(FPRegSet);
188210284Sjmallett  if (error.Fail())
189210284Sjmallett    return error;
190210284Sjmallett
191210284Sjmallett  data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
192210284Sjmallett  uint8_t *dst = data_sp->GetBytes();
193210284Sjmallett  ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
194210284Sjmallett
195210284Sjmallett  return error;
196210284Sjmallett}
197210284Sjmallett
198210284SjmallettStatus NativeRegisterContextFreeBSD_mips64::WriteAllRegisterValues(
199210284Sjmallett    const lldb::DataBufferSP &data_sp) {
200210284Sjmallett  Status error;
201210284Sjmallett
202210284Sjmallett  if (!data_sp) {
203210284Sjmallett    error.SetErrorStringWithFormat(
204210284Sjmallett        "NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided",
205210284Sjmallett        __FUNCTION__);
206210284Sjmallett    return error;
207210284Sjmallett  }
208
209  if (data_sp->GetByteSize() != m_reg_data.size()) {
210    error.SetErrorStringWithFormat(
211        "NativeRegisterContextFreeBSD_mips64::%s data_sp contained mismatched "
212        "data size, expected %" PRIu64 ", actual %" PRIu64,
213        __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
214    return error;
215  }
216
217  const uint8_t *src = data_sp->GetBytes();
218  if (src == nullptr) {
219    error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_mips64::%s "
220                                   "DataBuffer::GetBytes() returned a null "
221                                   "pointer",
222                                   __FUNCTION__);
223    return error;
224  }
225  ::memcpy(m_reg_data.data(), src, m_reg_data.size());
226
227  error = WriteRegisterSet(GPRegSet);
228  if (error.Fail())
229    return error;
230
231  return WriteRegisterSet(FPRegSet);
232}
233
234llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom(
235    NativeRegisterContextFreeBSD &source) {
236  return llvm::Error::success();
237}
238
239#endif // defined (__mips64__)
240