1*bee4d6efSMichał Górny //===-- NativeRegisterContextFreeBSD_arm.cpp ------------------------------===//
2*bee4d6efSMichał Górny //
3*bee4d6efSMichał Górny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*bee4d6efSMichał Górny // See https://llvm.org/LICENSE.txt for license information.
5*bee4d6efSMichał Górny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*bee4d6efSMichał Górny //
7*bee4d6efSMichał Górny //===----------------------------------------------------------------------===//
8*bee4d6efSMichał Górny 
9*bee4d6efSMichał Górny #if defined(__arm__)
10*bee4d6efSMichał Górny 
11*bee4d6efSMichał Górny #include "NativeRegisterContextFreeBSD_arm.h"
12*bee4d6efSMichał Górny 
13*bee4d6efSMichał Górny #include "lldb/Utility/DataBufferHeap.h"
14*bee4d6efSMichał Górny #include "lldb/Utility/RegisterValue.h"
15*bee4d6efSMichał Górny #include "lldb/Utility/Status.h"
16*bee4d6efSMichał Górny 
17*bee4d6efSMichał Górny #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
18*bee4d6efSMichał Górny #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
19*bee4d6efSMichał Górny 
20*bee4d6efSMichał Górny // clang-format off
21*bee4d6efSMichał Górny #include <sys/param.h>
22*bee4d6efSMichał Górny #include <sys/ptrace.h>
23*bee4d6efSMichał Górny #include <sys/types.h>
24*bee4d6efSMichał Górny // clang-format on
25*bee4d6efSMichał Górny 
26*bee4d6efSMichał Górny using namespace lldb;
27*bee4d6efSMichał Górny using namespace lldb_private;
28*bee4d6efSMichał Górny using namespace lldb_private::process_freebsd;
29*bee4d6efSMichał Górny 
30*bee4d6efSMichał Górny NativeRegisterContextFreeBSD *
31*bee4d6efSMichał Górny NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
32*bee4d6efSMichał Górny     const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
33*bee4d6efSMichał Górny   return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread);
34*bee4d6efSMichał Górny }
35*bee4d6efSMichał Górny 
36*bee4d6efSMichał Górny NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm(
37*bee4d6efSMichał Górny     const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
38*bee4d6efSMichał Górny     : NativeRegisterContextRegisterInfo(
39*bee4d6efSMichał Górny           native_thread, new RegisterInfoPOSIX_arm(target_arch)) {}
40*bee4d6efSMichał Górny 
41*bee4d6efSMichał Górny RegisterInfoPOSIX_arm &
42*bee4d6efSMichał Górny NativeRegisterContextFreeBSD_arm::GetRegisterInfo() const {
43*bee4d6efSMichał Górny   return static_cast<RegisterInfoPOSIX_arm &>(*m_register_info_interface_up);
44*bee4d6efSMichał Górny }
45*bee4d6efSMichał Górny 
46*bee4d6efSMichał Górny uint32_t NativeRegisterContextFreeBSD_arm::GetRegisterSetCount() const {
47*bee4d6efSMichał Górny   return GetRegisterInfo().GetRegisterSetCount();
48*bee4d6efSMichał Górny }
49*bee4d6efSMichał Górny 
50*bee4d6efSMichał Górny const RegisterSet *
51*bee4d6efSMichał Górny NativeRegisterContextFreeBSD_arm::GetRegisterSet(uint32_t set_index) const {
52*bee4d6efSMichał Górny   return GetRegisterInfo().GetRegisterSet(set_index);
53*bee4d6efSMichał Górny }
54*bee4d6efSMichał Górny 
55*bee4d6efSMichał Górny uint32_t NativeRegisterContextFreeBSD_arm::GetUserRegisterCount() const {
56*bee4d6efSMichał Górny   uint32_t count = 0;
57*bee4d6efSMichał Górny   for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
58*bee4d6efSMichał Górny     count += GetRegisterSet(set_index)->num_registers;
59*bee4d6efSMichał Górny   return count;
60*bee4d6efSMichał Górny }
61*bee4d6efSMichał Górny 
62*bee4d6efSMichał Górny Status NativeRegisterContextFreeBSD_arm::ReadRegisterSet(uint32_t set) {
63*bee4d6efSMichał Górny   switch (set) {
64*bee4d6efSMichał Górny   case RegisterInfoPOSIX_arm::GPRegSet:
65*bee4d6efSMichał Górny     return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
66*bee4d6efSMichał Górny                                                m_reg_data.data());
67*bee4d6efSMichał Górny   case RegisterInfoPOSIX_arm::FPRegSet:
68*bee4d6efSMichał Górny     return NativeProcessFreeBSD::PtraceWrapper(
69*bee4d6efSMichał Górny         PT_GETVFPREGS, m_thread.GetID(),
70*bee4d6efSMichał Górny         m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR));
71*bee4d6efSMichał Górny   }
72*bee4d6efSMichał Górny   llvm_unreachable("NativeRegisterContextFreeBSD_arm::ReadRegisterSet");
73*bee4d6efSMichał Górny }
74*bee4d6efSMichał Górny 
75*bee4d6efSMichał Górny Status NativeRegisterContextFreeBSD_arm::WriteRegisterSet(uint32_t set) {
76*bee4d6efSMichał Górny   switch (set) {
77*bee4d6efSMichał Górny   case RegisterInfoPOSIX_arm::GPRegSet:
78*bee4d6efSMichał Górny     return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
79*bee4d6efSMichał Górny                                                m_reg_data.data());
80*bee4d6efSMichał Górny   case RegisterInfoPOSIX_arm::FPRegSet:
81*bee4d6efSMichał Górny     return NativeProcessFreeBSD::PtraceWrapper(
82*bee4d6efSMichał Górny         PT_SETVFPREGS, m_thread.GetID(),
83*bee4d6efSMichał Górny         m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR));
84*bee4d6efSMichał Górny   }
85*bee4d6efSMichał Górny   llvm_unreachable("NativeRegisterContextFreeBSD_arm::WriteRegisterSet");
86*bee4d6efSMichał Górny }
87*bee4d6efSMichał Górny 
88*bee4d6efSMichał Górny Status
89*bee4d6efSMichał Górny NativeRegisterContextFreeBSD_arm::ReadRegister(const RegisterInfo *reg_info,
90*bee4d6efSMichał Górny                                                RegisterValue &reg_value) {
91*bee4d6efSMichał Górny   Status error;
92*bee4d6efSMichał Górny 
93*bee4d6efSMichał Górny   if (!reg_info) {
94*bee4d6efSMichał Górny     error.SetErrorString("reg_info NULL");
95*bee4d6efSMichał Górny     return error;
96*bee4d6efSMichał Górny   }
97*bee4d6efSMichał Górny 
98*bee4d6efSMichał Górny   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
99*bee4d6efSMichał Górny 
100*bee4d6efSMichał Górny   if (reg == LLDB_INVALID_REGNUM)
101*bee4d6efSMichał Górny     return Status("no lldb regnum for %s", reg_info && reg_info->name
102*bee4d6efSMichał Górny                                                ? reg_info->name
103*bee4d6efSMichał Górny                                                : "<unknown register>");
104*bee4d6efSMichał Górny 
105*bee4d6efSMichał Górny   uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
106*bee4d6efSMichał Górny   error = ReadRegisterSet(set);
107*bee4d6efSMichał Górny   if (error.Fail())
108*bee4d6efSMichał Górny     return error;
109*bee4d6efSMichał Górny 
110*bee4d6efSMichał Górny   assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
111*bee4d6efSMichał Górny   reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
112*bee4d6efSMichał Górny                      reg_info->byte_size, endian::InlHostByteOrder());
113*bee4d6efSMichał Górny   return error;
114*bee4d6efSMichał Górny }
115*bee4d6efSMichał Górny 
116*bee4d6efSMichał Górny Status NativeRegisterContextFreeBSD_arm::WriteRegister(
117*bee4d6efSMichał Górny     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
118*bee4d6efSMichał Górny   Status error;
119*bee4d6efSMichał Górny 
120*bee4d6efSMichał Górny   if (!reg_info)
121*bee4d6efSMichał Górny     return Status("reg_info NULL");
122*bee4d6efSMichał Górny 
123*bee4d6efSMichał Górny   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
124*bee4d6efSMichał Górny 
125*bee4d6efSMichał Górny   if (reg == LLDB_INVALID_REGNUM)
126*bee4d6efSMichał Górny     return Status("no lldb regnum for %s", reg_info && reg_info->name
127*bee4d6efSMichał Górny                                                ? reg_info->name
128*bee4d6efSMichał Górny                                                : "<unknown register>");
129*bee4d6efSMichał Górny 
130*bee4d6efSMichał Górny   uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
131*bee4d6efSMichał Górny   error = ReadRegisterSet(set);
132*bee4d6efSMichał Górny   if (error.Fail())
133*bee4d6efSMichał Górny     return error;
134*bee4d6efSMichał Górny 
135*bee4d6efSMichał Górny   assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
136*bee4d6efSMichał Górny   ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
137*bee4d6efSMichał Górny            reg_info->byte_size);
138*bee4d6efSMichał Górny 
139*bee4d6efSMichał Górny   return WriteRegisterSet(set);
140*bee4d6efSMichał Górny }
141*bee4d6efSMichał Górny 
142*bee4d6efSMichał Górny Status NativeRegisterContextFreeBSD_arm::ReadAllRegisterValues(
143*bee4d6efSMichał Górny     lldb::DataBufferSP &data_sp) {
144*bee4d6efSMichał Górny   Status error;
145*bee4d6efSMichał Górny 
146*bee4d6efSMichał Górny   error = ReadRegisterSet(RegisterInfoPOSIX_arm::GPRegSet);
147*bee4d6efSMichał Górny   if (error.Fail())
148*bee4d6efSMichał Górny     return error;
149*bee4d6efSMichał Górny 
150*bee4d6efSMichał Górny   error = ReadRegisterSet(RegisterInfoPOSIX_arm::FPRegSet);
151*bee4d6efSMichał Górny   if (error.Fail())
152*bee4d6efSMichał Górny     return error;
153*bee4d6efSMichał Górny 
154*bee4d6efSMichał Górny   data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
155*bee4d6efSMichał Górny   uint8_t *dst = data_sp->GetBytes();
156*bee4d6efSMichał Górny   ::memcpy(dst, m_reg_data.data(), m_reg_data.size());
157*bee4d6efSMichał Górny 
158*bee4d6efSMichał Górny   return error;
159*bee4d6efSMichał Górny }
160*bee4d6efSMichał Górny 
161*bee4d6efSMichał Górny Status NativeRegisterContextFreeBSD_arm::WriteAllRegisterValues(
162*bee4d6efSMichał Górny     const lldb::DataBufferSP &data_sp) {
163*bee4d6efSMichał Górny   Status error;
164*bee4d6efSMichał Górny 
165*bee4d6efSMichał Górny   if (!data_sp) {
166*bee4d6efSMichał Górny     error.SetErrorStringWithFormat(
167*bee4d6efSMichał Górny         "NativeRegisterContextFreeBSD_arm::%s invalid data_sp provided",
168*bee4d6efSMichał Górny         __FUNCTION__);
169*bee4d6efSMichał Górny     return error;
170*bee4d6efSMichał Górny   }
171*bee4d6efSMichał Górny 
172*bee4d6efSMichał Górny   if (data_sp->GetByteSize() != m_reg_data.size()) {
173*bee4d6efSMichał Górny     error.SetErrorStringWithFormat(
174*bee4d6efSMichał Górny         "NativeRegisterContextFreeBSD_arm::%s data_sp contained mismatched "
175*bee4d6efSMichał Górny         "data size, expected %" PRIu64 ", actual %" PRIu64,
176*bee4d6efSMichał Górny         __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
177*bee4d6efSMichał Górny     return error;
178*bee4d6efSMichał Górny   }
179*bee4d6efSMichał Górny 
180*bee4d6efSMichał Górny   uint8_t *src = data_sp->GetBytes();
181*bee4d6efSMichał Górny   if (src == nullptr) {
182*bee4d6efSMichał Górny     error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm::%s "
183*bee4d6efSMichał Górny                                    "DataBuffer::GetBytes() returned a null "
184*bee4d6efSMichał Górny                                    "pointer",
185*bee4d6efSMichał Górny                                    __FUNCTION__);
186*bee4d6efSMichał Górny     return error;
187*bee4d6efSMichał Górny   }
188*bee4d6efSMichał Górny   ::memcpy(m_reg_data.data(), src, m_reg_data.size());
189*bee4d6efSMichał Górny 
190*bee4d6efSMichał Górny   error = WriteRegisterSet(RegisterInfoPOSIX_arm::GPRegSet);
191*bee4d6efSMichał Górny   if (error.Fail())
192*bee4d6efSMichał Górny     return error;
193*bee4d6efSMichał Górny 
194*bee4d6efSMichał Górny   return WriteRegisterSet(RegisterInfoPOSIX_arm::FPRegSet);
195*bee4d6efSMichał Górny }
196*bee4d6efSMichał Górny 
197*bee4d6efSMichał Górny llvm::Error NativeRegisterContextFreeBSD_arm::CopyHardwareWatchpointsFrom(
198*bee4d6efSMichał Górny     NativeRegisterContextFreeBSD &source) {
199*bee4d6efSMichał Górny   return llvm::Error::success();
200*bee4d6efSMichał Górny }
201*bee4d6efSMichał Górny 
202*bee4d6efSMichał Górny #endif // defined (__arm__)
203