forked from OSchip/llvm-project
Support custom expedited register set in gdb-remote
This patch adds capability to introduce a custom expedited register set in gdb remote. Currently we send register set 0 as expedited register set but for the case of AArch64 SVE we intend to send additional information about SVE registers size/offset configuration which can be calculated from vg register. Therefore we will expedited Vg register in case of AArch64 is in SVE mode to speedup register configuration calculations. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D82853
This commit is contained in:
parent
5110ff0817
commit
b69c09bf43
|
@ -16,6 +16,8 @@ namespace lldb_private {
|
||||||
|
|
||||||
class NativeThreadProtocol;
|
class NativeThreadProtocol;
|
||||||
|
|
||||||
|
enum class ExpeditedRegs { Minimal, Full };
|
||||||
|
|
||||||
class NativeRegisterContext
|
class NativeRegisterContext
|
||||||
: public std::enable_shared_from_this<NativeRegisterContext> {
|
: public std::enable_shared_from_this<NativeRegisterContext> {
|
||||||
public:
|
public:
|
||||||
|
@ -116,6 +118,9 @@ public:
|
||||||
|
|
||||||
virtual NativeThreadProtocol &GetThread() { return m_thread; }
|
virtual NativeThreadProtocol &GetThread() { return m_thread; }
|
||||||
|
|
||||||
|
virtual std::vector<uint32_t>
|
||||||
|
GetExpeditedRegisters(ExpeditedRegs expType) const;
|
||||||
|
|
||||||
const RegisterInfo *GetRegisterInfoByName(llvm::StringRef reg_name,
|
const RegisterInfo *GetRegisterInfoByName(llvm::StringRef reg_name,
|
||||||
uint32_t start_idx = 0);
|
uint32_t start_idx = 0);
|
||||||
|
|
||||||
|
|
|
@ -424,3 +424,32 @@ NativeRegisterContext::ConvertRegisterKindToRegisterNumber(uint32_t kind,
|
||||||
|
|
||||||
return LLDB_INVALID_REGNUM;
|
return LLDB_INVALID_REGNUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t>
|
||||||
|
NativeRegisterContext::GetExpeditedRegisters(ExpeditedRegs expType) const {
|
||||||
|
if (expType == ExpeditedRegs::Minimal) {
|
||||||
|
// Expedite only a minimum set of important generic registers.
|
||||||
|
static const uint32_t k_expedited_registers[] = {
|
||||||
|
LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP,
|
||||||
|
LLDB_REGNUM_GENERIC_RA};
|
||||||
|
|
||||||
|
std::vector<uint32_t> expedited_reg_nums;
|
||||||
|
for (uint32_t gen_reg : k_expedited_registers) {
|
||||||
|
uint32_t reg_num =
|
||||||
|
ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, gen_reg);
|
||||||
|
if (reg_num == LLDB_INVALID_REGNUM)
|
||||||
|
continue; // Target does not support the given register.
|
||||||
|
else
|
||||||
|
expedited_reg_nums.push_back(reg_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
return expedited_reg_nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetRegisterSetCount() > 0 && expType == ExpeditedRegs::Full)
|
||||||
|
return std::vector<uint32_t>(GetRegisterSet(0)->registers,
|
||||||
|
GetRegisterSet(0)->registers +
|
||||||
|
GetRegisterSet(0)->num_registers);
|
||||||
|
|
||||||
|
return std::vector<uint32_t>();
|
||||||
|
}
|
||||||
|
|
|
@ -503,7 +503,7 @@ static void WriteRegisterValueInHexFixedWidth(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Expected<json::Object>
|
static llvm::Optional<json::Object>
|
||||||
GetRegistersAsJSON(NativeThreadProtocol &thread) {
|
GetRegistersAsJSON(NativeThreadProtocol &thread) {
|
||||||
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
|
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
|
||||||
|
|
||||||
|
@ -512,30 +512,16 @@ GetRegistersAsJSON(NativeThreadProtocol &thread) {
|
||||||
json::Object register_object;
|
json::Object register_object;
|
||||||
|
|
||||||
#ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET
|
#ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET
|
||||||
// Expedite all registers in the first register set (i.e. should be GPRs)
|
const auto expedited_regs =
|
||||||
// that are not contained in other registers.
|
reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
|
||||||
const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0);
|
|
||||||
if (!reg_set_p)
|
|
||||||
return llvm::make_error<llvm::StringError>("failed to get registers",
|
|
||||||
llvm::inconvertibleErrorCode());
|
|
||||||
for (const uint32_t *reg_num_p = reg_set_p->registers;
|
|
||||||
*reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) {
|
|
||||||
uint32_t reg_num = *reg_num_p;
|
|
||||||
#else
|
#else
|
||||||
// Expedite only a couple of registers until we figure out why sending
|
const auto expedited_regs =
|
||||||
// registers is expensive.
|
reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Minimal);
|
||||||
static const uint32_t k_expedited_registers[] = {
|
|
||||||
LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP,
|
|
||||||
LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM};
|
|
||||||
|
|
||||||
for (const uint32_t *generic_reg_p = k_expedited_registers;
|
|
||||||
*generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) {
|
|
||||||
uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
|
|
||||||
eRegisterKindGeneric, *generic_reg_p);
|
|
||||||
if (reg_num == LLDB_INVALID_REGNUM)
|
|
||||||
continue; // Target does not support the given register.
|
|
||||||
#endif
|
#endif
|
||||||
|
if (expedited_regs.empty())
|
||||||
|
return llvm::None;
|
||||||
|
|
||||||
|
for (auto ®_num : expedited_regs) {
|
||||||
const RegisterInfo *const reg_info_p =
|
const RegisterInfo *const reg_info_p =
|
||||||
reg_ctx.GetRegisterInfoAtIndex(reg_num);
|
reg_ctx.GetRegisterInfoAtIndex(reg_num);
|
||||||
if (reg_info_p == nullptr) {
|
if (reg_info_p == nullptr) {
|
||||||
|
@ -628,12 +614,8 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) {
|
||||||
json::Object thread_obj;
|
json::Object thread_obj;
|
||||||
|
|
||||||
if (!abridged) {
|
if (!abridged) {
|
||||||
if (llvm::Expected<json::Object> registers =
|
if (llvm::Optional<json::Object> registers = GetRegistersAsJSON(*thread))
|
||||||
GetRegistersAsJSON(*thread)) {
|
|
||||||
thread_obj.try_emplace("registers", std::move(*registers));
|
thread_obj.try_emplace("registers", std::move(*registers));
|
||||||
} else {
|
|
||||||
return registers.takeError();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_obj.try_emplace("tid", static_cast<int64_t>(tid));
|
thread_obj.try_emplace("tid", static_cast<int64_t>(tid));
|
||||||
|
@ -814,46 +796,27 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
|
||||||
|
|
||||||
// Grab the register context.
|
// Grab the register context.
|
||||||
NativeRegisterContext& reg_ctx = thread->GetRegisterContext();
|
NativeRegisterContext& reg_ctx = thread->GetRegisterContext();
|
||||||
// Expedite all registers in the first register set (i.e. should be GPRs)
|
const auto expedited_regs =
|
||||||
// that are not contained in other registers.
|
reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
|
||||||
const RegisterSet *reg_set_p;
|
|
||||||
if (reg_ctx.GetRegisterSetCount() > 0 &&
|
|
||||||
((reg_set_p = reg_ctx.GetRegisterSet(0)) != nullptr)) {
|
|
||||||
LLDB_LOGF(log,
|
|
||||||
"GDBRemoteCommunicationServerLLGS::%s expediting registers "
|
|
||||||
"from set '%s' (registers set count: %zu)",
|
|
||||||
__FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>",
|
|
||||||
reg_set_p->num_registers);
|
|
||||||
|
|
||||||
for (const uint32_t *reg_num_p = reg_set_p->registers;
|
for (auto ®_num : expedited_regs) {
|
||||||
*reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) {
|
|
||||||
const RegisterInfo *const reg_info_p =
|
const RegisterInfo *const reg_info_p =
|
||||||
reg_ctx.GetRegisterInfoAtIndex(*reg_num_p);
|
reg_ctx.GetRegisterInfoAtIndex(reg_num);
|
||||||
if (reg_info_p == nullptr) {
|
|
||||||
LLDB_LOGF(log,
|
|
||||||
"GDBRemoteCommunicationServerLLGS::%s failed to get "
|
|
||||||
"register info for register set '%s', register index "
|
|
||||||
"%" PRIu32,
|
|
||||||
__FUNCTION__,
|
|
||||||
reg_set_p->name ? reg_set_p->name : "<unnamed-set>",
|
|
||||||
*reg_num_p);
|
|
||||||
} else if (reg_info_p->value_regs == nullptr) {
|
|
||||||
// Only expediate registers that are not contained in other registers.
|
// Only expediate registers that are not contained in other registers.
|
||||||
|
if (reg_info_p != nullptr && reg_info_p->value_regs == nullptr) {
|
||||||
RegisterValue reg_value;
|
RegisterValue reg_value;
|
||||||
Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
|
Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
|
||||||
if (error.Success()) {
|
if (error.Success()) {
|
||||||
response.Printf("%.02x:", *reg_num_p);
|
response.Printf("%.02x:", reg_num);
|
||||||
WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
|
WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
|
||||||
®_value, lldb::eByteOrderBig);
|
®_value, lldb::eByteOrderBig);
|
||||||
response.PutChar(';');
|
response.PutChar(';');
|
||||||
} else {
|
} else {
|
||||||
LLDB_LOGF(log,
|
LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to read "
|
||||||
"GDBRemoteCommunicationServerLLGS::%s failed to read "
|
|
||||||
"register '%s' index %" PRIu32 ": %s",
|
"register '%s' index %" PRIu32 ": %s",
|
||||||
__FUNCTION__,
|
__FUNCTION__,
|
||||||
reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
|
reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
|
||||||
*reg_num_p, error.AsCString());
|
reg_num, error.AsCString());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue