Skip to content

Commit 5352ea4

Browse files
committed
[lldb] [ABI/X86] Support combining xmm* and ymm*h regs into ymm*
gdbserver does not expose combined ymm* registers but rather XSAVE-style split xmm* and ymm*h portions. Extend value_regs to support combining multiple registers and use it to create user-friendly ymm* registers that are combined from split xmm* and ymm*h portions. Differential Revision: https://reviews.llvm.org/D108937
1 parent cf65271 commit 5352ea4

File tree

6 files changed

+290
-115
lines changed

6 files changed

+290
-115
lines changed

lldb/include/lldb/lldb-private-types.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ struct RegisterInfo {
5151
/// List of registers (terminated with LLDB_INVALID_REGNUM). If this value is
5252
/// not null, all registers in this list will be read first, at which point
5353
/// the value for this register will be valid. For example, the value list
54-
/// for ah would be eax (x86) or rax (x64).
55-
uint32_t *value_regs; //
54+
/// for ah would be eax (x86) or rax (x64). Register numbers are
55+
/// of eRegisterKindLLDB. If multiple registers are listed, the final
56+
/// value will be the concatenation of them.
57+
uint32_t *value_regs;
5658
/// List of registers (terminated with LLDB_INVALID_REGNUM). If this value is
5759
/// not null, all registers in this list will be invalidated when the value of
5860
/// this register changes. For example, the invalidate list for eax would be

lldb/source/Plugins/ABI/X86/ABIX86.cpp

Lines changed: 168 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -33,36 +33,40 @@ void ABIX86::Terminate() {
3333
ABIWindows_x86_64::Terminate();
3434
}
3535

36-
enum class RegKind {
37-
GPR32 = 0,
36+
namespace {
37+
enum RegKind {
38+
GPR32,
3839
GPR16,
3940
GPR8h,
4041
GPR8,
42+
MM,
43+
YMM_YMMh,
44+
YMM_XMM,
4145

42-
MM = 0,
46+
RegKindCount
47+
};
48+
};
49+
50+
struct RegData {
51+
RegKind subreg_kind;
52+
llvm::StringRef subreg_name;
53+
llvm::Optional<uint32_t> base_index;
4354
};
4455

45-
typedef llvm::SmallDenseMap<llvm::StringRef,
46-
llvm::SmallVector<llvm::StringRef, 4>, 16>
47-
RegisterMap;
48-
49-
static void addPartialRegisters(
50-
std::vector<DynamicRegisterInfo::Register> &regs,
51-
llvm::ArrayRef<uint32_t> base_reg_indices, const RegisterMap &reg_names,
52-
uint32_t base_size, RegKind name_index, lldb::Encoding encoding,
53-
lldb::Format format, uint32_t subreg_size, uint32_t subreg_offset = 0) {
54-
for (uint32_t base_index : base_reg_indices) {
55-
if (base_index == LLDB_INVALID_REGNUM)
56-
break;
57-
assert(base_index < regs.size());
56+
static void
57+
addPartialRegisters(std::vector<DynamicRegisterInfo::Register> &regs,
58+
llvm::ArrayRef<RegData *> subregs, uint32_t base_size,
59+
lldb::Encoding encoding, lldb::Format format,
60+
uint32_t subreg_size, uint32_t subreg_offset = 0) {
61+
for (const RegData *subreg : subregs) {
62+
assert(subreg);
63+
uint32_t base_index = subreg->base_index.getValue();
5864
DynamicRegisterInfo::Register &full_reg = regs[base_index];
59-
llvm::StringRef subreg_name = reg_names.lookup(
60-
full_reg.name.GetStringRef())[static_cast<int>(name_index)];
61-
if (subreg_name.empty() || full_reg.byte_size != base_size)
65+
if (full_reg.byte_size != base_size)
6266
continue;
6367

64-
lldb_private::DynamicRegisterInfo::Register subreg{
65-
lldb_private::ConstString(subreg_name),
68+
lldb_private::DynamicRegisterInfo::Register new_reg{
69+
lldb_private::ConstString(subreg->subreg_name),
6670
lldb_private::ConstString(),
6771
lldb_private::ConstString("supplementary registers"),
6872
subreg_size,
@@ -77,10 +81,112 @@ static void addPartialRegisters(
7781
{},
7882
subreg_offset};
7983

80-
addSupplementaryRegister(regs, subreg);
84+
addSupplementaryRegister(regs, new_reg);
85+
}
86+
}
87+
88+
static void
89+
addCombinedRegisters(std::vector<DynamicRegisterInfo::Register> &regs,
90+
llvm::ArrayRef<RegData *> subregs1,
91+
llvm::ArrayRef<RegData *> subregs2, uint32_t base_size,
92+
lldb::Encoding encoding, lldb::Format format) {
93+
for (auto it : llvm::zip(subregs1, subregs2)) {
94+
RegData *regdata1, *regdata2;
95+
std::tie(regdata1, regdata2) = it;
96+
assert(regdata1);
97+
assert(regdata2);
98+
99+
// verify that we've got matching target registers
100+
if (regdata1->subreg_name != regdata2->subreg_name)
101+
continue;
102+
103+
uint32_t base_index1 = regdata1->base_index.getValue();
104+
uint32_t base_index2 = regdata2->base_index.getValue();
105+
if (regs[base_index1].byte_size != base_size ||
106+
regs[base_index2].byte_size != base_size)
107+
continue;
108+
109+
lldb_private::DynamicRegisterInfo::Register new_reg{
110+
lldb_private::ConstString(regdata1->subreg_name),
111+
lldb_private::ConstString(),
112+
lldb_private::ConstString("supplementary registers"),
113+
base_size * 2,
114+
LLDB_INVALID_INDEX32,
115+
encoding,
116+
format,
117+
LLDB_INVALID_REGNUM,
118+
LLDB_INVALID_REGNUM,
119+
LLDB_INVALID_REGNUM,
120+
LLDB_INVALID_REGNUM,
121+
{base_index1, base_index2},
122+
{}};
123+
124+
addSupplementaryRegister(regs, new_reg);
81125
}
82126
}
83127

128+
typedef llvm::SmallDenseMap<llvm::StringRef, llvm::SmallVector<RegData, 4>, 64>
129+
BaseRegToRegsMap;
130+
131+
#define GPRh(l) \
132+
{ \
133+
is64bit ? BaseRegToRegsMap::value_type("r" l "x", {{GPR32, "e" l "x"}, \
134+
{GPR16, l "x"}, \
135+
{GPR8h, l "h"}, \
136+
{GPR8, l "l"}}) \
137+
: BaseRegToRegsMap::value_type( \
138+
"e" l "x", {{GPR16, l "x"}, {GPR8h, l "h"}, {GPR8, l "l"}}) \
139+
}
140+
141+
#define GPR(r16) \
142+
{ \
143+
is64bit ? BaseRegToRegsMap::value_type( \
144+
"r" r16, {{GPR32, "e" r16}, {GPR16, r16}, {GPR8, r16 "l"}}) \
145+
: BaseRegToRegsMap::value_type("e" r16, \
146+
{{GPR16, r16}, {GPR8, r16 "l"}}) \
147+
}
148+
149+
#define GPR64(n) \
150+
{ \
151+
BaseRegToRegsMap::value_type( \
152+
"r" #n, \
153+
{{GPR32, "r" #n "d"}, {GPR16, "r" #n "w"}, {GPR8, "r" #n "l"}}) \
154+
}
155+
156+
#define STMM(n) \
157+
{ BaseRegToRegsMap::value_type("st" #n, {{MM, "mm" #n}}) }
158+
159+
#define YMM(n) \
160+
{BaseRegToRegsMap::value_type("ymm" #n "h", {{YMM_YMMh, "ymm" #n}})}, { \
161+
BaseRegToRegsMap::value_type("xmm" #n, {{YMM_XMM, "ymm" #n}}) \
162+
}
163+
164+
BaseRegToRegsMap makeBaseRegMap(bool is64bit) {
165+
BaseRegToRegsMap out{
166+
{// GPRs common to amd64 & i386
167+
GPRh("a"), GPRh("b"), GPRh("c"), GPRh("d"), GPR("si"), GPR("di"),
168+
GPR("bp"), GPR("sp"),
169+
170+
// ST/MM registers
171+
STMM(0), STMM(1), STMM(2), STMM(3), STMM(4), STMM(5), STMM(6), STMM(7),
172+
173+
// lower YMM registers (common to amd64 & i386)
174+
YMM(0), YMM(1), YMM(2), YMM(3), YMM(4), YMM(5), YMM(6), YMM(7)}};
175+
176+
if (is64bit) {
177+
BaseRegToRegsMap amd64_regs{{// GPRs specific to amd64
178+
GPR64(8), GPR64(9), GPR64(10), GPR64(11),
179+
GPR64(12), GPR64(13), GPR64(14), GPR64(15),
180+
181+
// higher YMM registers (specific to amd64)
182+
YMM(8), YMM(9), YMM(10), YMM(11), YMM(12),
183+
YMM(13), YMM(14), YMM(15)}};
184+
out.insert(amd64_regs.begin(), amd64_regs.end());
185+
}
186+
187+
return out;
188+
}
189+
84190
void ABIX86::AugmentRegisterInfo(
85191
std::vector<DynamicRegisterInfo::Register> &regs) {
86192
MCBasedABI::AugmentRegisterInfo(regs);
@@ -91,83 +197,54 @@ void ABIX86::AugmentRegisterInfo(
91197

92198
uint32_t gpr_base_size =
93199
process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
94-
bool is64bit = gpr_base_size == 8;
95-
96-
typedef RegisterMap::value_type RegPair;
97-
#define GPR_BASE(basename) (is64bit ? "r" basename : "e" basename)
98-
RegisterMap gpr_regs{{
99-
RegPair(GPR_BASE("ax"), {"eax", "ax", "ah", "al"}),
100-
RegPair(GPR_BASE("bx"), {"ebx", "bx", "bh", "bl"}),
101-
RegPair(GPR_BASE("cx"), {"ecx", "cx", "ch", "cl"}),
102-
RegPair(GPR_BASE("dx"), {"edx", "dx", "dh", "dl"}),
103-
RegPair(GPR_BASE("si"), {"esi", "si", "", "sil"}),
104-
RegPair(GPR_BASE("di"), {"edi", "di", "", "dil"}),
105-
RegPair(GPR_BASE("bp"), {"ebp", "bp", "", "bpl"}),
106-
RegPair(GPR_BASE("sp"), {"esp", "sp", "", "spl"}),
107-
}};
108-
#undef GPR_BASE
109-
if (is64bit) {
110-
#define R(base) RegPair(base, {base "d", base "w", "", base "l"})
111-
RegisterMap amd64_regs{{
112-
R("r8"),
113-
R("r9"),
114-
R("r10"),
115-
R("r11"),
116-
R("r12"),
117-
R("r13"),
118-
R("r14"),
119-
R("r15"),
120-
}};
121-
#undef R
122-
gpr_regs.insert(amd64_regs.begin(), amd64_regs.end());
123-
}
124200

125-
RegisterMap st_regs{{
126-
RegPair("st0", {"mm0"}),
127-
RegPair("st1", {"mm1"}),
128-
RegPair("st2", {"mm2"}),
129-
RegPair("st3", {"mm3"}),
130-
RegPair("st4", {"mm4"}),
131-
RegPair("st5", {"mm5"}),
132-
RegPair("st6", {"mm6"}),
133-
RegPair("st7", {"mm7"}),
134-
}};
135-
136-
// regs from gpr_basenames, in list order
137-
std::vector<uint32_t> gpr_base_reg_indices;
138-
// st0..st7, in list order
139-
std::vector<uint32_t> st_reg_indices;
140-
// map used for fast register lookups
201+
// primary map from a base register to its subregisters
202+
BaseRegToRegsMap base_reg_map = makeBaseRegMap(gpr_base_size == 8);
203+
// set used for fast matching of register names to subregisters
141204
llvm::SmallDenseSet<llvm::StringRef, 64> subreg_name_set;
142-
143-
// put all subreg names into the lookup set
144-
for (const RegisterMap &regset : {gpr_regs, st_regs}) {
145-
for (const RegPair &kv : regset)
146-
subreg_name_set.insert(kv.second.begin(), kv.second.end());
205+
// convenience array providing access to all subregisters of given kind,
206+
// sorted by base register index
207+
std::array<llvm::SmallVector<RegData *, 16>, RegKindCount> subreg_by_kind;
208+
209+
// prepare the set of all known subregisters
210+
for (const auto &x : base_reg_map) {
211+
for (const auto &subreg : x.second)
212+
subreg_name_set.insert(subreg.subreg_name);
147213
}
148214

215+
// iterate over all registers
149216
for (const auto &x : llvm::enumerate(regs)) {
150217
llvm::StringRef reg_name = x.value().name.GetStringRef();
151-
// find expected base registers
152-
if (gpr_regs.find(reg_name) != gpr_regs.end())
153-
gpr_base_reg_indices.push_back(x.index());
154-
else if (st_regs.find(reg_name) != st_regs.end())
155-
st_reg_indices.push_back(x.index());
156218
// abort if at least one sub-register is already present
157-
else if (llvm::is_contained(subreg_name_set, reg_name))
219+
if (llvm::is_contained(subreg_name_set, reg_name))
158220
return;
221+
222+
auto found = base_reg_map.find(reg_name);
223+
if (found == base_reg_map.end())
224+
continue;
225+
226+
for (auto &subreg : found->second) {
227+
// fill in base register indices
228+
subreg.base_index = x.index();
229+
// fill subreg_by_kind map-array
230+
subreg_by_kind[static_cast<size_t>(subreg.subreg_kind)].push_back(
231+
&subreg);
232+
}
159233
}
160234

161-
if (is64bit)
162-
addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size,
163-
RegKind::GPR32, eEncodingUint, eFormatHex, 4);
164-
addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size,
165-
RegKind::GPR16, eEncodingUint, eFormatHex, 2);
166-
addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size,
167-
RegKind::GPR8h, eEncodingUint, eFormatHex, 1, 1);
168-
addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size,
169-
RegKind::GPR8, eEncodingUint, eFormatHex, 1);
170-
171-
addPartialRegisters(regs, st_reg_indices, st_regs, 10, RegKind::MM,
172-
eEncodingUint, eFormatHex, 8);
235+
// now add registers by kind
236+
addPartialRegisters(regs, subreg_by_kind[GPR32], gpr_base_size, eEncodingUint,
237+
eFormatHex, 4);
238+
addPartialRegisters(regs, subreg_by_kind[GPR16], gpr_base_size, eEncodingUint,
239+
eFormatHex, 2);
240+
addPartialRegisters(regs, subreg_by_kind[GPR8h], gpr_base_size, eEncodingUint,
241+
eFormatHex, 1, 1);
242+
addPartialRegisters(regs, subreg_by_kind[GPR8], gpr_base_size, eEncodingUint,
243+
eFormatHex, 1);
244+
245+
addPartialRegisters(regs, subreg_by_kind[MM], 10, eEncodingUint, eFormatHex,
246+
8);
247+
248+
addCombinedRegisters(regs, subreg_by_kind[YMM_XMM], subreg_by_kind[YMM_YMMh],
249+
16, eEncodingVector, eFormatVectorOfUInt8);
173250
}

lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,34 @@ bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info,
8787
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
8888
if (m_reg_valid[reg] == false)
8989
return false;
90-
const bool partial_data_ok = false;
91-
Status error(value.SetValueFromData(
92-
reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
93-
return error.Success();
90+
if (reg_info->value_regs &&
91+
reg_info->value_regs[0] != LLDB_INVALID_REGNUM &&
92+
reg_info->value_regs[1] != LLDB_INVALID_REGNUM) {
93+
std::vector<char> combined_data;
94+
uint32_t offset = 0;
95+
for (int i = 0; reg_info->value_regs[i] != LLDB_INVALID_REGNUM; i++) {
96+
const RegisterInfo *parent_reg = GetRegisterInfo(
97+
eRegisterKindLLDB, reg_info->value_regs[i]);
98+
if (!parent_reg)
99+
return false;
100+
combined_data.resize(offset + parent_reg->byte_size);
101+
if (m_reg_data.CopyData(parent_reg->byte_offset, parent_reg->byte_size,
102+
combined_data.data() + offset) !=
103+
parent_reg->byte_size)
104+
return false;
105+
offset += parent_reg->byte_size;
106+
}
107+
108+
Status error;
109+
return value.SetFromMemoryData(
110+
reg_info, combined_data.data(), combined_data.size(),
111+
m_reg_data.GetByteOrder(), error) == combined_data.size();
112+
} else {
113+
const bool partial_data_ok = false;
114+
Status error(value.SetValueFromData(
115+
reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
116+
return error.Success();
117+
}
94118
}
95119
return false;
96120
}
@@ -272,8 +296,38 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info) {
272296
bool GDBRemoteRegisterContext::WriteRegister(const RegisterInfo *reg_info,
273297
const RegisterValue &value) {
274298
DataExtractor data;
275-
if (value.GetData(data))
276-
return WriteRegisterBytes(reg_info, data, 0);
299+
if (value.GetData(data)) {
300+
if (reg_info->value_regs &&
301+
reg_info->value_regs[0] != LLDB_INVALID_REGNUM &&
302+
reg_info->value_regs[1] != LLDB_INVALID_REGNUM) {
303+
uint32_t combined_size = 0;
304+
for (int i = 0; reg_info->value_regs[i] != LLDB_INVALID_REGNUM; i++) {
305+
const RegisterInfo *parent_reg = GetRegisterInfo(
306+
eRegisterKindLLDB, reg_info->value_regs[i]);
307+
if (!parent_reg)
308+
return false;
309+
combined_size += parent_reg->byte_size;
310+
}
311+
312+
if (data.GetByteSize() < combined_size)
313+
return false;
314+
315+
uint32_t offset = 0;
316+
for (int i = 0; reg_info->value_regs[i] != LLDB_INVALID_REGNUM; i++) {
317+
const RegisterInfo *parent_reg = GetRegisterInfo(
318+
eRegisterKindLLDB, reg_info->value_regs[i]);
319+
assert(parent_reg);
320+
321+
DataExtractor parent_data{data, offset, parent_reg->byte_size};
322+
if (!WriteRegisterBytes(parent_reg, parent_data, 0))
323+
return false;
324+
offset += parent_reg->byte_size;
325+
}
326+
assert(offset == combined_size);
327+
return true;
328+
} else
329+
return WriteRegisterBytes(reg_info, data, 0);
330+
}
277331
return false;
278332
}
279333

0 commit comments

Comments
 (0)