LLDB mainline
RegisterContextPOSIX_x86.cpp
Go to the documentation of this file.
1//===-- RegisterContextPOSIX_x86.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#include <cerrno>
10#include <cstdint>
11#include <cstring>
12
13#include "lldb/Target/Process.h"
14#include "lldb/Target/Target.h"
15#include "lldb/Target/Thread.h"
18#include "lldb/Utility/Endian.h"
20#include "lldb/Utility/Scalar.h"
21#include "llvm/Support/Compiler.h"
22
25
26using namespace lldb_private;
27using namespace lldb;
28
41static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) -
42 1 ==
44 "g_gpr_regnums_i386 has wrong number of register infos");
45
59static_assert((sizeof(g_lldb_regnums_i386) / sizeof(g_lldb_regnums_i386[0])) -
60 1 ==
62 "g_lldb_regnums_i386 has wrong number of register infos");
63
64const uint32_t g_avx_regnums_i386[] = {
67 LLDB_INVALID_REGNUM // Register sets must be terminated with
68 // LLDB_INVALID_REGNUM.
69};
70static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) -
71 1 ==
73 " g_avx_regnums_i386 has wrong number of register infos");
74
75static const uint32_t g_gpr_regnums_x86_64[] = {
84 lldb_r8d_x86_64, // Low 32 bits or r8
85 lldb_r9d_x86_64, // Low 32 bits or r9
86 lldb_r10d_x86_64, // Low 32 bits or r10
87 lldb_r11d_x86_64, // Low 32 bits or r11
88 lldb_r12d_x86_64, // Low 32 bits or r12
89 lldb_r13d_x86_64, // Low 32 bits or r13
90 lldb_r14d_x86_64, // Low 32 bits or r14
91 lldb_r15d_x86_64, // Low 32 bits or r15
94 lldb_r8w_x86_64, // Low 16 bits or r8
95 lldb_r9w_x86_64, // Low 16 bits or r9
96 lldb_r10w_x86_64, // Low 16 bits or r10
97 lldb_r11w_x86_64, // Low 16 bits or r11
98 lldb_r12w_x86_64, // Low 16 bits or r12
99 lldb_r13w_x86_64, // Low 16 bits or r13
100 lldb_r14w_x86_64, // Low 16 bits or r14
101 lldb_r15w_x86_64, // Low 16 bits or r15
105 lldb_r8l_x86_64, // Low 8 bits or r8
106 lldb_r9l_x86_64, // Low 8 bits or r9
107 lldb_r10l_x86_64, // Low 8 bits or r10
108 lldb_r11l_x86_64, // Low 8 bits or r11
109 lldb_r12l_x86_64, // Low 8 bits or r12
110 lldb_r13l_x86_64, // Low 8 bits or r13
111 lldb_r14l_x86_64, // Low 8 bits or r14
112 lldb_r15l_x86_64, // Low 8 bits or r15
113 LLDB_INVALID_REGNUM // Register sets must be terminated with
114 // LLDB_INVALID_REGNUM.
115};
116static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
117 1 ==
119 "g_gpr_regnums_x86_64 has wrong number of register infos");
120
140static_assert((sizeof(g_lldb_regnums_x86_64) /
141 sizeof(g_lldb_regnums_x86_64[0])) -
142 1 ==
144 "g_lldb_regnums_x86_64 has wrong number of register infos");
145
154static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) -
155 1 ==
157 "g_avx_regnums_x86_64 has wrong number of register infos");
158
159// Number of register sets provided by this context.
161
163 {"General Purpose Registers", "gpr", k_num_gpr_registers_i386,
165 {"Floating Point Registers", "fpu", k_num_fpr_registers_i386,
167 {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
169
171 {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
173 {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
175 {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
177
179 return reg <= GetRegInfo().last_gpr; // GPR's come first.
180}
181
183 return (GetRegInfo().first_fpr <= reg && reg <= GetRegInfo().last_fpr);
184}
185
187 return (GetRegInfo().first_ymm <= reg && reg <= GetRegInfo().last_ymm);
188}
189
190bool RegisterContextPOSIX_x86::IsFPR(unsigned reg, FPRType fpr_type) {
191 bool generic_fpr = IsFPR(reg);
192
193 if (fpr_type == eXSAVE)
194 return generic_fpr || IsAVX(reg);
195 return generic_fpr;
196}
197
199 Thread &thread, uint32_t concrete_frame_idx,
200 RegisterInfoInterface *register_info)
201 : RegisterContext(thread, concrete_frame_idx) {
202 m_register_info_up.reset(register_info);
203
204 ::memset(&m_fpr, 0, sizeof(FPR));
205 ::memset(&m_ymm_set, 0, sizeof(YMM));
206
208}
209
211
213 if (m_fpr_type == eNotValid) {
214 // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx
215 m_fpr_type = eXSAVE; // extended floating-point registers, if available
216 if (!ReadFPR())
217 m_fpr_type = eFXSAVE; // assume generic floating-point registers
218 }
219 return m_fpr_type;
220}
221
223
225
227 assert(reg < GetRegInfo().num_registers && "Invalid register number.");
228 return GetRegisterInfo()[reg].byte_offset;
229}
230
232 return GetRegInfoShared(
233 m_register_info_up->GetTargetArchitecture().GetMachine(),
234 /*with_base=*/false);
235}
236
238 assert(reg < GetRegInfo().num_registers && "Invalid register number.");
239 return GetRegisterInfo()[reg].byte_size;
240}
241
243 size_t num_registers =
245 if (GetFPRType() == eXSAVE)
246 return num_registers + GetRegInfo().num_avx_registers;
247 return num_registers;
248}
249
251 return m_register_info_up->GetGPRSize();
252}
253
257
259 // Commonly, this method is overridden and g_register_infos is copied and
260 // specialized. So, use GetRegisterInfo() rather than g_register_infos in
261 // this scope.
262 return m_register_info_up->GetRegisterInfo();
263}
264
265const RegisterInfo *
267 if (reg < GetRegInfo().num_registers)
268 return &GetRegisterInfo()[reg];
269 else
270 return nullptr;
271}
272
274 size_t sets = 0;
275 for (size_t set = 0; set < k_num_register_sets; ++set) {
276 if (IsRegisterSetAvailable(set))
277 ++sets;
278 }
279
280 return sets;
281}
282
284 if (IsRegisterSetAvailable(set)) {
285 switch (m_register_info_up->GetTargetArchitecture().GetMachine()) {
286 case llvm::Triple::x86:
287 return &g_reg_sets_i386[set];
288 case llvm::Triple::x86_64:
289 return &g_reg_sets_x86_64[set];
290 default:
291 assert(false && "Unhandled target architecture.");
292 return nullptr;
293 }
294 }
295 return nullptr;
296}
297
299 assert(reg < GetRegInfo().num_registers && "Invalid register offset.");
300 return GetRegisterInfo()[reg].name;
301}
302
303// Parse ymm registers and into xmm.bytes and ymmh.bytes.
305 lldb::ByteOrder byte_order) {
306 if (!IsAVX(reg))
307 return false;
308
309 if (byte_order == eByteOrderLittle) {
310 uint32_t reg_no = reg - GetRegInfo().first_ymm;
311 YMMToXState(m_ymm_set.ymm[reg_no], m_fpr.fxsave.xmm[reg_no].bytes,
312 m_fpr.xsave.ymmh[reg_no].bytes);
313 return true;
314 }
315
316 return false; // unsupported or invalid byte order
317}
318
319// Concatenate xmm.bytes with ymmh.bytes
321 lldb::ByteOrder byte_order) {
322 if (!IsAVX(reg))
323 return false;
324
325 if (byte_order == eByteOrderLittle) {
326 uint32_t reg_no = reg - GetRegInfo().first_ymm;
327 m_ymm_set.ymm[reg_no] = XStateToYMM(m_fpr.fxsave.xmm[reg_no].bytes,
328 m_fpr.xsave.ymmh[reg_no].bytes);
329 return true;
330 }
331
332 return false; // unsupported or invalid byte order
333}
334
336 // Note: Extended register sets are assumed to be at the end of g_reg_sets...
338
339 if (GetFPRType() == eXSAVE) // ...and to start with AVX registers.
340 ++num_sets;
341 return (set_index < num_sets);
342}
const uint32_t g_lldb_regnums_i386[]
static const RegisterSet g_reg_sets_i386[]
static const uint32_t g_gpr_regnums_x86_64[]
static const uint32_t g_lldb_regnums_x86_64[]
const uint32_t g_gpr_regnums_i386[]
static const RegisterSet g_reg_sets_x86_64[]
const uint32_t g_avx_regnums_i386[]
static const uint32_t g_avx_regnums_x86_64[]
@ k_num_extended_register_sets
std::unique_ptr< lldb_private::RegisterInfoInterface > m_register_info_up
~RegisterContextPOSIX_x86() override
const lldb_private::RegisterInfo * GetRegisterInfoAtIndex(size_t reg) override
bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order)
virtual unsigned GetRegisterOffset(unsigned reg)
virtual bool IsRegisterSetAvailable(size_t set_index)
virtual bool ReadFPR()=0
const lldb_private::RegisterSet * GetRegisterSet(size_t set) override
virtual const lldb_private::RegisterInfo * GetRegisterInfo()
RegisterContextPOSIX_x86(lldb_private::Thread &thread, uint32_t concrete_frame_idx, lldb_private::RegisterInfoInterface *register_info)
virtual unsigned GetRegisterSize(unsigned reg)
virtual lldb_private::RegInfo & GetRegInfo()
const char * GetRegisterName(unsigned reg)
bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
RegisterContext(Thread &thread, uint32_t concrete_frame_idx)
RegisterInfo interface to patch RegisterInfo structure for archs.
#define LLDB_INVALID_REGNUM
A class that represents a running process on the host machine.
RegInfo & GetRegInfoShared(llvm::Triple::ArchType arch_type, bool with_base)
void YMMToXState(const YMMReg &input, void *xmm_bytes, void *ymmh_bytes)
YMMReg XStateToYMM(const void *xmm_bytes, const void *ymmh_bytes)
ByteOrder
Byte ordering definitions.
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_offset
The byte offset in the register context data where this register's value is found.
uint32_t byte_size
Size in bytes of the register.
const char * name
Name of this register, can't be NULL.
Registers are grouped into register sets.