Files
llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
Muhammad Omair Javaid 78cb4562fa Make offset field optional in RegisterInfo packet for Arm64
This patch carries forward our aim to remove offset field from qRegisterInfo
packets and XML register description. I have created a new function which
returns if offset fields are dynamic meaning client can calculate offset on
its own based on register number sequence and register size. For now this
function only returns true for NativeRegisterContextLinux_arm64 but we can
test this for other architectures and make it standard later.

As a consequence we do not send offset field from lldb-server (arm64 for now)
while other stubs dont have an offset field so it wont effect them for now.
On the client side we have replaced previous offset calculation algorithm
with a new scheme, where we sort all primary registers in increasing
order of remote regnum and then calculate offset incrementally.

This committ also includes a test to verify all of above functionality
on Arm64.

Reviewed By: labath

Differential Revision: https://reviews.llvm.org/D91241
2020-12-02 03:19:43 +05:00

778 lines
31 KiB
C++

//===-- DynamicRegisterInfo.cpp -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "DynamicRegisterInfo.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Host/StringConvert.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/StringExtractor.h"
#include "lldb/Utility/StructuredData.h"
using namespace lldb;
using namespace lldb_private;
DynamicRegisterInfo::DynamicRegisterInfo(
const lldb_private::StructuredData::Dictionary &dict,
const lldb_private::ArchSpec &arch) {
SetRegisterInfo(dict, arch);
}
DynamicRegisterInfo::DynamicRegisterInfo(DynamicRegisterInfo &&info) {
MoveFrom(std::move(info));
}
DynamicRegisterInfo &
DynamicRegisterInfo::operator=(DynamicRegisterInfo &&info) {
MoveFrom(std::move(info));
return *this;
}
void DynamicRegisterInfo::MoveFrom(DynamicRegisterInfo &&info) {
m_regs = std::move(info.m_regs);
m_sets = std::move(info.m_sets);
m_set_reg_nums = std::move(info.m_set_reg_nums);
m_set_names = std::move(info.m_set_names);
m_value_regs_map = std::move(info.m_value_regs_map);
m_invalidate_regs_map = std::move(info.m_invalidate_regs_map);
m_dynamic_reg_size_map = std::move(info.m_dynamic_reg_size_map);
m_reg_data_byte_size = info.m_reg_data_byte_size;
m_finalized = info.m_finalized;
if (m_finalized) {
const size_t num_sets = m_sets.size();
for (size_t set = 0; set < num_sets; ++set)
m_sets[set].registers = m_set_reg_nums[set].data();
}
info.Clear();
}
size_t
DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
const ArchSpec &arch) {
assert(!m_finalized);
StructuredData::Array *sets = nullptr;
if (dict.GetValueForKeyAsArray("sets", sets)) {
const uint32_t num_sets = sets->GetSize();
for (uint32_t i = 0; i < num_sets; ++i) {
ConstString set_name;
if (sets->GetItemAtIndexAsString(i, set_name) && !set_name.IsEmpty()) {
m_sets.push_back({set_name.AsCString(), nullptr, 0, nullptr});
} else {
Clear();
printf("error: register sets must have valid names\n");
return 0;
}
}
m_set_reg_nums.resize(m_sets.size());
}
StructuredData::Array *regs = nullptr;
if (!dict.GetValueForKeyAsArray("registers", regs))
return 0;
const uint32_t num_regs = regs->GetSize();
// typedef std::map<std::string, std::vector<std::string> >
// InvalidateNameMap;
// InvalidateNameMap invalidate_map;
for (uint32_t i = 0; i < num_regs; ++i) {
StructuredData::Dictionary *reg_info_dict = nullptr;
if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict)) {
Clear();
printf("error: items in the 'registers' array must be dictionaries\n");
regs->DumpToStdout();
return 0;
}
// { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16,
// 'encoding':'uint' , 'format':'hex' , 'set': 0, 'ehframe' : 2,
// 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
RegisterInfo reg_info;
std::vector<uint32_t> value_regs;
std::vector<uint32_t> invalidate_regs;
memset(&reg_info, 0, sizeof(reg_info));
ConstString name_val;
ConstString alt_name_val;
if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr)) {
Clear();
printf("error: registers must have valid names and offsets\n");
reg_info_dict->DumpToStdout();
return 0;
}
reg_info.name = name_val.GetCString();
reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val, nullptr);
reg_info.alt_name = alt_name_val.GetCString();
reg_info_dict->GetValueForKeyAsInteger("offset", reg_info.byte_offset,
UINT32_MAX);
const ByteOrder byte_order = arch.GetByteOrder();
if (reg_info.byte_offset == UINT32_MAX) {
// No offset for this register, see if the register has a value
// expression which indicates this register is part of another register.
// Value expressions are things like "rax[31:0]" which state that the
// current register's value is in a concrete register "rax" in bits 31:0.
// If there is a value expression we can calculate the offset
bool success = false;
llvm::StringRef slice_str;
if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr)) {
// Slices use the following format:
// REGNAME[MSBIT:LSBIT]
// REGNAME - name of the register to grab a slice of
// MSBIT - the most significant bit at which the current register value
// starts at
// LSBIT - the least significant bit at which the current register value
// ends at
static RegularExpression g_bitfield_regex(
llvm::StringRef("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]"));
llvm::SmallVector<llvm::StringRef, 4> matches;
if (g_bitfield_regex.Execute(slice_str, &matches)) {
std::string reg_name_str = matches[1].str();
std::string msbit_str = matches[2].str();
std::string lsbit_str = matches[3].str();
const uint32_t msbit =
StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX);
const uint32_t lsbit =
StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX);
if (msbit != UINT32_MAX && lsbit != UINT32_MAX) {
if (msbit > lsbit) {
const uint32_t msbyte = msbit / 8;
const uint32_t lsbyte = lsbit / 8;
const RegisterInfo *containing_reg_info =
GetRegisterInfo(reg_name_str);
if (containing_reg_info) {
const uint32_t max_bit = containing_reg_info->byte_size * 8;
if (msbit < max_bit && lsbit < max_bit) {
m_invalidate_regs_map[containing_reg_info
->kinds[eRegisterKindLLDB]]
.push_back(i);
m_value_regs_map[i].push_back(
containing_reg_info->kinds[eRegisterKindLLDB]);
m_invalidate_regs_map[i].push_back(
containing_reg_info->kinds[eRegisterKindLLDB]);
if (byte_order == eByteOrderLittle) {
success = true;
reg_info.byte_offset =
containing_reg_info->byte_offset + lsbyte;
} else if (byte_order == eByteOrderBig) {
success = true;
reg_info.byte_offset =
containing_reg_info->byte_offset + msbyte;
} else {
llvm_unreachable("Invalid byte order");
}
} else {
if (msbit > max_bit)
printf("error: msbit (%u) must be less than the bitsize "
"of the register (%u)\n",
msbit, max_bit);
else
printf("error: lsbit (%u) must be less than the bitsize "
"of the register (%u)\n",
lsbit, max_bit);
}
} else {
printf("error: invalid concrete register \"%s\"\n",
reg_name_str.c_str());
}
} else {
printf("error: msbit (%u) must be greater than lsbit (%u)\n",
msbit, lsbit);
}
} else {
printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit,
lsbit);
}
} else {
// TODO: print error invalid slice string that doesn't follow the
// format
printf("error: failed to match against register bitfield regex\n");
}
} else {
StructuredData::Array *composite_reg_list = nullptr;
if (reg_info_dict->GetValueForKeyAsArray("composite",
composite_reg_list)) {
const size_t num_composite_regs = composite_reg_list->GetSize();
if (num_composite_regs > 0) {
uint32_t composite_offset = UINT32_MAX;
for (uint32_t composite_idx = 0; composite_idx < num_composite_regs;
++composite_idx) {
ConstString composite_reg_name;
if (composite_reg_list->GetItemAtIndexAsString(
composite_idx, composite_reg_name, nullptr)) {
const RegisterInfo *composite_reg_info =
GetRegisterInfo(composite_reg_name.GetStringRef());
if (composite_reg_info) {
composite_offset = std::min(composite_offset,
composite_reg_info->byte_offset);
m_value_regs_map[i].push_back(
composite_reg_info->kinds[eRegisterKindLLDB]);
m_invalidate_regs_map[composite_reg_info
->kinds[eRegisterKindLLDB]]
.push_back(i);
m_invalidate_regs_map[i].push_back(
composite_reg_info->kinds[eRegisterKindLLDB]);
} else {
// TODO: print error invalid slice string that doesn't follow
// the format
printf("error: failed to find composite register by name: "
"\"%s\"\n",
composite_reg_name.GetCString());
}
} else {
printf(
"error: 'composite' list value wasn't a python string\n");
}
}
if (composite_offset != UINT32_MAX) {
reg_info.byte_offset = composite_offset;
success = m_value_regs_map.find(i) != m_value_regs_map.end();
} else {
printf("error: 'composite' registers must specify at least one "
"real register\n");
}
} else {
printf("error: 'composite' list was empty\n");
}
}
}
if (!success) {
Clear();
reg_info_dict->DumpToStdout();
return 0;
}
}
int64_t bitsize = 0;
if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize)) {
Clear();
printf("error: invalid or missing 'bitsize' key/value pair in register "
"dictionary\n");
reg_info_dict->DumpToStdout();
return 0;
}
reg_info.byte_size = bitsize / 8;
llvm::StringRef dwarf_opcode_string;
if (reg_info_dict->GetValueForKeyAsString("dynamic_size_dwarf_expr_bytes",
dwarf_opcode_string)) {
reg_info.dynamic_size_dwarf_len = dwarf_opcode_string.size() / 2;
assert(reg_info.dynamic_size_dwarf_len > 0);
std::vector<uint8_t> dwarf_opcode_bytes(reg_info.dynamic_size_dwarf_len);
uint32_t j;
StringExtractor opcode_extractor(dwarf_opcode_string);
uint32_t ret_val = opcode_extractor.GetHexBytesAvail(dwarf_opcode_bytes);
UNUSED_IF_ASSERT_DISABLED(ret_val);
assert(ret_val == reg_info.dynamic_size_dwarf_len);
for (j = 0; j < reg_info.dynamic_size_dwarf_len; ++j)
m_dynamic_reg_size_map[i].push_back(dwarf_opcode_bytes[j]);
reg_info.dynamic_size_dwarf_expr_bytes = m_dynamic_reg_size_map[i].data();
}
llvm::StringRef format_str;
if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) {
if (OptionArgParser::ToFormat(format_str.str().c_str(), reg_info.format,
nullptr)
.Fail()) {
Clear();
printf("error: invalid 'format' value in register dictionary\n");
reg_info_dict->DumpToStdout();
return 0;
}
} else {
reg_info_dict->GetValueForKeyAsInteger("format", reg_info.format,
eFormatHex);
}
llvm::StringRef encoding_str;
if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str))
reg_info.encoding = Args::StringToEncoding(encoding_str, eEncodingUint);
else
reg_info_dict->GetValueForKeyAsInteger("encoding", reg_info.encoding,
eEncodingUint);
size_t set = 0;
if (!reg_info_dict->GetValueForKeyAsInteger<size_t>("set", set, -1) ||
set >= m_sets.size()) {
Clear();
printf("error: invalid 'set' value in register dictionary, valid values "
"are 0 - %i\n",
(int)set);
reg_info_dict->DumpToStdout();
return 0;
}
// Fill in the register numbers
reg_info.kinds[lldb::eRegisterKindLLDB] = i;
reg_info.kinds[lldb::eRegisterKindProcessPlugin] = i;
uint32_t eh_frame_regno = LLDB_INVALID_REGNUM;
reg_info_dict->GetValueForKeyAsInteger("gcc", eh_frame_regno,
LLDB_INVALID_REGNUM);
if (eh_frame_regno == LLDB_INVALID_REGNUM)
reg_info_dict->GetValueForKeyAsInteger("ehframe", eh_frame_regno,
LLDB_INVALID_REGNUM);
reg_info.kinds[lldb::eRegisterKindEHFrame] = eh_frame_regno;
reg_info_dict->GetValueForKeyAsInteger(
"dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM);
llvm::StringRef generic_str;
if (reg_info_dict->GetValueForKeyAsString("generic", generic_str))
reg_info.kinds[lldb::eRegisterKindGeneric] =
Args::StringToGenericRegister(generic_str);
else
reg_info_dict->GetValueForKeyAsInteger(
"generic", reg_info.kinds[lldb::eRegisterKindGeneric],
LLDB_INVALID_REGNUM);
// Check if this register invalidates any other register values when it is
// modified
StructuredData::Array *invalidate_reg_list = nullptr;
if (reg_info_dict->GetValueForKeyAsArray("invalidate-regs",
invalidate_reg_list)) {
const size_t num_regs = invalidate_reg_list->GetSize();
if (num_regs > 0) {
for (uint32_t idx = 0; idx < num_regs; ++idx) {
ConstString invalidate_reg_name;
uint64_t invalidate_reg_num;
if (invalidate_reg_list->GetItemAtIndexAsString(
idx, invalidate_reg_name)) {
const RegisterInfo *invalidate_reg_info =
GetRegisterInfo(invalidate_reg_name.GetStringRef());
if (invalidate_reg_info) {
m_invalidate_regs_map[i].push_back(
invalidate_reg_info->kinds[eRegisterKindLLDB]);
} else {
// TODO: print error invalid slice string that doesn't follow the
// format
printf("error: failed to find a 'invalidate-regs' register for "
"\"%s\" while parsing register \"%s\"\n",
invalidate_reg_name.GetCString(), reg_info.name);
}
} else if (invalidate_reg_list->GetItemAtIndexAsInteger(
idx, invalidate_reg_num)) {
if (invalidate_reg_num != UINT64_MAX)
m_invalidate_regs_map[i].push_back(invalidate_reg_num);
else
printf("error: 'invalidate-regs' list value wasn't a valid "
"integer\n");
} else {
printf("error: 'invalidate-regs' list value wasn't a python string "
"or integer\n");
}
}
} else {
printf("error: 'invalidate-regs' contained an empty list\n");
}
}
// Calculate the register offset
const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
if (m_reg_data_byte_size < end_reg_offset)
m_reg_data_byte_size = end_reg_offset;
m_regs.push_back(reg_info);
m_set_reg_nums[set].push_back(i);
}
Finalize(arch);
return m_regs.size();
}
void DynamicRegisterInfo::AddRegister(RegisterInfo &reg_info,
ConstString &reg_name,
ConstString &reg_alt_name,
ConstString &set_name) {
assert(!m_finalized);
const uint32_t reg_num = m_regs.size();
reg_info.name = reg_name.AsCString();
assert(reg_info.name);
reg_info.alt_name = reg_alt_name.AsCString(nullptr);
uint32_t i;
if (reg_info.value_regs) {
for (i = 0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i)
m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]);
}
if (reg_info.invalidate_regs) {
for (i = 0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i)
m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]);
}
if (reg_info.dynamic_size_dwarf_expr_bytes) {
for (i = 0; i < reg_info.dynamic_size_dwarf_len; ++i)
m_dynamic_reg_size_map[reg_num].push_back(
reg_info.dynamic_size_dwarf_expr_bytes[i]);
reg_info.dynamic_size_dwarf_expr_bytes =
m_dynamic_reg_size_map[reg_num].data();
}
m_regs.push_back(reg_info);
uint32_t set = GetRegisterSetIndexByName(set_name, true);
assert(set < m_sets.size());
assert(set < m_set_reg_nums.size());
assert(set < m_set_names.size());
m_set_reg_nums[set].push_back(reg_num);
}
void DynamicRegisterInfo::Finalize(const ArchSpec &arch) {
if (m_finalized)
return;
m_finalized = true;
const size_t num_sets = m_sets.size();
for (size_t set = 0; set < num_sets; ++set) {
assert(m_sets.size() == m_set_reg_nums.size());
m_sets[set].num_registers = m_set_reg_nums[set].size();
m_sets[set].registers = m_set_reg_nums[set].data();
}
// We are going to create a map between remote (eRegisterKindProcessPlugin)
// and local (eRegisterKindLLDB) register numbers. This map will give us
// remote register numbers in increasing order for offset calculation.
std::map<uint32_t, uint32_t> remote_to_local_regnum_map;
for (const auto &reg : m_regs)
remote_to_local_regnum_map[reg.kinds[eRegisterKindProcessPlugin]] =
reg.kinds[eRegisterKindLLDB];
// At this stage we manually calculate g/G packet offsets of all primary
// registers, only if target XML or qRegisterInfo packet did not send
// an offset explicitly.
uint32_t reg_offset = 0;
for (auto const &regnum_pair : remote_to_local_regnum_map) {
if (m_regs[regnum_pair.second].byte_offset == LLDB_INVALID_INDEX32 &&
m_regs[regnum_pair.second].value_regs == nullptr) {
m_regs[regnum_pair.second].byte_offset = reg_offset;
reg_offset = m_regs[regnum_pair.second].byte_offset +
m_regs[regnum_pair.second].byte_size;
}
}
// sort and unique all value registers and make sure each is terminated with
// LLDB_INVALID_REGNUM
for (reg_to_regs_map::iterator pos = m_value_regs_map.begin(),
end = m_value_regs_map.end();
pos != end; ++pos) {
if (pos->second.size() > 1) {
llvm::sort(pos->second.begin(), pos->second.end());
reg_num_collection::iterator unique_end =
std::unique(pos->second.begin(), pos->second.end());
if (unique_end != pos->second.end())
pos->second.erase(unique_end, pos->second.end());
}
assert(!pos->second.empty());
if (pos->second.back() != LLDB_INVALID_REGNUM)
pos->second.push_back(LLDB_INVALID_REGNUM);
}
// Now update all value_regs with each register info as needed
const size_t num_regs = m_regs.size();
for (size_t i = 0; i < num_regs; ++i) {
if (m_value_regs_map.find(i) != m_value_regs_map.end()) {
m_regs[i].value_regs = m_value_regs_map[i].data();
// Assign a valid offset to all pseudo registers if not assigned by stub.
// Pseudo registers with value_regs list populated will share same offset
// as that of their corresponding primary register in value_regs list.
if (m_regs[i].byte_offset == LLDB_INVALID_INDEX32) {
uint32_t value_regnum = m_regs[i].value_regs[0];
if (value_regnum != LLDB_INVALID_INDEX32)
m_regs[i].byte_offset =
GetRegisterInfoAtIndex(remote_to_local_regnum_map[value_regnum])
->byte_offset;
}
} else
m_regs[i].value_regs = nullptr;
reg_offset = m_regs[i].byte_offset + m_regs[i].byte_size;
if (m_reg_data_byte_size < reg_offset)
m_reg_data_byte_size = reg_offset;
}
// Expand all invalidation dependencies
for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(),
end = m_invalidate_regs_map.end();
pos != end; ++pos) {
const uint32_t reg_num = pos->first;
if (m_regs[reg_num].value_regs) {
reg_num_collection extra_invalid_regs;
for (const uint32_t invalidate_reg_num : pos->second) {
reg_to_regs_map::iterator invalidate_pos =
m_invalidate_regs_map.find(invalidate_reg_num);
if (invalidate_pos != m_invalidate_regs_map.end()) {
for (const uint32_t concrete_invalidate_reg_num :
invalidate_pos->second) {
if (concrete_invalidate_reg_num != reg_num)
extra_invalid_regs.push_back(concrete_invalidate_reg_num);
}
}
}
pos->second.insert(pos->second.end(), extra_invalid_regs.begin(),
extra_invalid_regs.end());
}
}
// sort and unique all invalidate registers and make sure each is terminated
// with LLDB_INVALID_REGNUM
for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(),
end = m_invalidate_regs_map.end();
pos != end; ++pos) {
if (pos->second.size() > 1) {
llvm::sort(pos->second.begin(), pos->second.end());
reg_num_collection::iterator unique_end =
std::unique(pos->second.begin(), pos->second.end());
if (unique_end != pos->second.end())
pos->second.erase(unique_end, pos->second.end());
}
assert(!pos->second.empty());
if (pos->second.back() != LLDB_INVALID_REGNUM)
pos->second.push_back(LLDB_INVALID_REGNUM);
}
// Now update all invalidate_regs with each register info as needed
for (size_t i = 0; i < num_regs; ++i) {
if (m_invalidate_regs_map.find(i) != m_invalidate_regs_map.end())
m_regs[i].invalidate_regs = m_invalidate_regs_map[i].data();
else
m_regs[i].invalidate_regs = nullptr;
}
// Check if we need to automatically set the generic registers in case they
// weren't set
bool generic_regs_specified = false;
for (const auto &reg : m_regs) {
if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) {
generic_regs_specified = true;
break;
}
}
if (!generic_regs_specified) {
switch (arch.GetMachine()) {
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
for (auto &reg : m_regs) {
if (strcmp(reg.name, "pc") == 0)
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
else if ((strcmp(reg.name, "fp") == 0) ||
(strcmp(reg.name, "x29") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
else if ((strcmp(reg.name, "lr") == 0) ||
(strcmp(reg.name, "x30") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
else if ((strcmp(reg.name, "sp") == 0) ||
(strcmp(reg.name, "x31") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
else if (strcmp(reg.name, "cpsr") == 0)
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
}
break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
for (auto &reg : m_regs) {
if ((strcmp(reg.name, "pc") == 0) || (strcmp(reg.name, "r15") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
else if ((strcmp(reg.name, "sp") == 0) ||
(strcmp(reg.name, "r13") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
else if ((strcmp(reg.name, "lr") == 0) ||
(strcmp(reg.name, "r14") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
else if ((strcmp(reg.name, "r7") == 0) &&
arch.GetTriple().getVendor() == llvm::Triple::Apple)
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
else if ((strcmp(reg.name, "r11") == 0) &&
arch.GetTriple().getVendor() != llvm::Triple::Apple)
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
else if (strcmp(reg.name, "fp") == 0)
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
else if (strcmp(reg.name, "cpsr") == 0)
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
}
break;
case llvm::Triple::x86:
for (auto &reg : m_regs) {
if ((strcmp(reg.name, "eip") == 0) || (strcmp(reg.name, "pc") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
else if ((strcmp(reg.name, "esp") == 0) ||
(strcmp(reg.name, "sp") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
else if ((strcmp(reg.name, "ebp") == 0) ||
(strcmp(reg.name, "fp") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
else if ((strcmp(reg.name, "eflags") == 0) ||
(strcmp(reg.name, "flags") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
}
break;
case llvm::Triple::x86_64:
for (auto &reg : m_regs) {
if ((strcmp(reg.name, "rip") == 0) || (strcmp(reg.name, "pc") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
else if ((strcmp(reg.name, "rsp") == 0) ||
(strcmp(reg.name, "sp") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
else if ((strcmp(reg.name, "rbp") == 0) ||
(strcmp(reg.name, "fp") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
else if ((strcmp(reg.name, "rflags") == 0) ||
(strcmp(reg.name, "flags") == 0))
reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
}
break;
default:
break;
}
}
}
size_t DynamicRegisterInfo::GetNumRegisters() const { return m_regs.size(); }
size_t DynamicRegisterInfo::GetNumRegisterSets() const { return m_sets.size(); }
size_t DynamicRegisterInfo::GetRegisterDataByteSize() const {
return m_reg_data_byte_size;
}
const RegisterInfo *
DynamicRegisterInfo::GetRegisterInfoAtIndex(uint32_t i) const {
if (i < m_regs.size())
return &m_regs[i];
return nullptr;
}
RegisterInfo *DynamicRegisterInfo::GetRegisterInfoAtIndex(uint32_t i) {
if (i < m_regs.size())
return &m_regs[i];
return nullptr;
}
const RegisterSet *DynamicRegisterInfo::GetRegisterSet(uint32_t i) const {
if (i < m_sets.size())
return &m_sets[i];
return nullptr;
}
uint32_t DynamicRegisterInfo::GetRegisterSetIndexByName(ConstString &set_name,
bool can_create) {
name_collection::iterator pos, end = m_set_names.end();
for (pos = m_set_names.begin(); pos != end; ++pos) {
if (*pos == set_name)
return std::distance(m_set_names.begin(), pos);
}
m_set_names.push_back(set_name);
m_set_reg_nums.resize(m_set_reg_nums.size() + 1);
RegisterSet new_set = {set_name.AsCString(), nullptr, 0, nullptr};
m_sets.push_back(new_set);
return m_sets.size() - 1;
}
uint32_t
DynamicRegisterInfo::ConvertRegisterKindToRegisterNumber(uint32_t kind,
uint32_t num) const {
reg_collection::const_iterator pos, end = m_regs.end();
for (pos = m_regs.begin(); pos != end; ++pos) {
if (pos->kinds[kind] == num)
return std::distance(m_regs.begin(), pos);
}
return LLDB_INVALID_REGNUM;
}
void DynamicRegisterInfo::Clear() {
m_regs.clear();
m_sets.clear();
m_set_reg_nums.clear();
m_set_names.clear();
m_value_regs_map.clear();
m_invalidate_regs_map.clear();
m_dynamic_reg_size_map.clear();
m_reg_data_byte_size = 0;
m_finalized = false;
}
void DynamicRegisterInfo::Dump() const {
StreamFile s(stdout, false);
const size_t num_regs = m_regs.size();
s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n",
static_cast<const void *>(this), static_cast<uint64_t>(num_regs));
for (size_t i = 0; i < num_regs; ++i) {
s.Printf("[%3" PRIu64 "] name = %-10s", (uint64_t)i, m_regs[i].name);
s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s",
m_regs[i].byte_size, m_regs[i].byte_offset, m_regs[i].encoding,
FormatManager::GetFormatAsCString(m_regs[i].format));
if (m_regs[i].kinds[eRegisterKindProcessPlugin] != LLDB_INVALID_REGNUM)
s.Printf(", process plugin = %3u",
m_regs[i].kinds[eRegisterKindProcessPlugin]);
if (m_regs[i].kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
s.Printf(", dwarf = %3u", m_regs[i].kinds[eRegisterKindDWARF]);
if (m_regs[i].kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM)
s.Printf(", ehframe = %3u", m_regs[i].kinds[eRegisterKindEHFrame]);
if (m_regs[i].kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM)
s.Printf(", generic = %3u", m_regs[i].kinds[eRegisterKindGeneric]);
if (m_regs[i].alt_name)
s.Printf(", alt-name = %s", m_regs[i].alt_name);
if (m_regs[i].value_regs) {
s.Printf(", value_regs = [ ");
for (size_t j = 0; m_regs[i].value_regs[j] != LLDB_INVALID_REGNUM; ++j) {
s.Printf("%s ", m_regs[m_regs[i].value_regs[j]].name);
}
s.Printf("]");
}
if (m_regs[i].invalidate_regs) {
s.Printf(", invalidate_regs = [ ");
for (size_t j = 0; m_regs[i].invalidate_regs[j] != LLDB_INVALID_REGNUM;
++j) {
s.Printf("%s ", m_regs[m_regs[i].invalidate_regs[j]].name);
}
s.Printf("]");
}
s.EOL();
}
const size_t num_sets = m_sets.size();
s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " register sets:\n",
static_cast<const void *>(this), static_cast<uint64_t>(num_sets));
for (size_t i = 0; i < num_sets; ++i) {
s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i,
m_sets[i].name);
for (size_t idx = 0; idx < m_sets[i].num_registers; ++idx) {
s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name);
}
s.Printf("]\n");
}
}
const lldb_private::RegisterInfo *
DynamicRegisterInfo::GetRegisterInfo(llvm::StringRef reg_name) const {
for (auto &reg_info : m_regs)
if (reg_info.name == reg_name)
return &reg_info;
return nullptr;
}