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