Index: include/lldb/lldb-private-types.h =================================================================== --- include/lldb/lldb-private-types.h +++ include/lldb/lldb-private-types.h @@ -54,6 +54,8 @@ // null, all registers in this list will be invalidated when the value of this // register changes. For example, the invalidate list for eax would be rax // ax, ah, and al. + uint8_t dynamic_size; // if this value is 1 then size of this register is decided at run time. + // Default value is 0 }; //---------------------------------------------------------------------- Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h @@ -33,6 +33,9 @@ uint32_t GetRegisterSetCount () const override; + const RegisterInfo * + GetRegisterInfoAtIndex (uint32_t reg_index) const override; + lldb::addr_t GetPCfromBreakpointLocation (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS) override; @@ -113,6 +116,9 @@ bool IsFR0(); + void + IsFR1_FRE (bool &fr1, bool &fre) const; + bool IsFRE(); Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -483,6 +483,32 @@ return k_num_register_sets; } + +const RegisterInfo * +NativeRegisterContextLinux_mips64::GetRegisterInfoAtIndex (uint32_t reg_index) const +{ + if (reg_index <= GetRegisterCount ()) + { + const RegisterInfoInterface& reg_info_interface = GetRegisterInfoInterface (); + RegisterInfo* reg_info = const_cast(reg_info_interface.GetRegisterInfo ()) + reg_index; + + if (reg_info->dynamic_size) + { + bool fre; + bool fr1; + IsFR1_FRE (fr1, fre); + + // fr1 fre fpu_reg_size + // 1 0 64 + // 1 1 32 + // 0 0 32 + reg_info->byte_size = (fr1 ^ fre) ? 8 : 4; + } + return const_cast(reg_info); + } + return nullptr; +} + lldb::addr_t NativeRegisterContextLinux_mips64::GetPCfromBreakpointLocation (lldb::addr_t fail_value) { @@ -901,6 +927,42 @@ return (!(value & SR_FR)); } +void +NativeRegisterContextLinux_mips64::IsFR1_FRE (bool& fr1, bool& fre) const +{ + GPR_linux_mips regs; + RegisterValue reg_value; + const RegisterInfoInterface& reg_info_interface = GetRegisterInfoInterface (); + const RegisterInfo* reg_info_sr = reg_info_interface.GetRegisterInfo () + gpr_sr_mips64 ; + const RegisterInfo* reg_info_config5 = reg_info_interface.GetRegisterInfo () + gpr_config5_mips; + lldb_private::ArchSpec arch; + ::memset (®s, 0, sizeof(GPR_linux_mips)); + + fre = 0; + if (!(m_thread.GetProcess ()->GetArchitecture (arch))) + assert (false && "Failed to get Architecture."); + + errno = 0; + + // Reading SR/Config5 using PTRACE_PEEKUSER is not supported. So read entire register set + Error error = NativeProcessLinux::PtraceWrapper (PTRACE_GETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); + if (!error.Success()) + assert (false && "Unable to Read Register"); + + void* target_address = ((uint8_t*)®s) + reg_info_sr->byte_offset + 4 * (arch.GetMachine () == llvm::Triple::mips); + reg_value.SetBytes (target_address, 4, arch.GetByteOrder()); + fr1 = reg_value.GetAsUInt32() & SR_FR; + + // FRE is valid only when FR bit is set + if (fr1) + { + target_address = ((uint8_t*)®s) + reg_info_config5->byte_offset + + 4 * (arch.GetMachine () == llvm::Triple::mips); + reg_value.SetBytes(target_address, 4, arch.GetByteOrder ()); + fre = reg_value.GetAsUInt32() & CONFIG5_FRE; + } +} + bool NativeRegisterContextLinux_mips64::IsFRE() { Index: source/Plugins/Process/Utility/DynamicRegisterInfo.cpp =================================================================== --- source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -291,6 +291,10 @@ } reg_info.byte_size = bitsize / 8; + + uint8_t dynamic_size = 0; + reg_info_dict->GetValueForKeyAsInteger("dynamic_size", dynamic_size); + reg_info.dynamic_size = dynamic_size; std::string format_str; if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) @@ -702,11 +706,12 @@ for (size_t i=0; ireg), FPR_OFFSET(reg), eEncodingIEEE754, \ - eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL } + eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL, 1} #define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((FPR_linux_mips*)NULL)->reg), FPR_OFFSET(reg), eEncodingUint, \ Index: source/Plugins/Process/Utility/RegisterInfos_mips64.h =================================================================== --- source/Plugins/Process/Utility/RegisterInfos_mips64.h +++ source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -57,7 +57,7 @@ #define DEFINE_FPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((FPR_linux_mips*)0)->reg), FPR_OFFSET(reg), eEncodingIEEE754, \ - eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL } + eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL, 1} #define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((FPR_linux_mips*)0)->reg), FPR_OFFSET(reg), eEncodingUint, \ Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1634,6 +1634,10 @@ response.PutChar (';'); } + if (reg_info->dynamic_size) + { + response.Printf ("dynamic_size:%" PRIu32 ";", 1); + } return SendPacketNoLock(response.GetData(), response.GetSize()); } Index: source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -46,6 +46,13 @@ void HardcodeARMRegisters(bool from_scratch); + + // Detect the register size dynamically. + bool + UpdateDynamicRegisterSize (ExecutionContext *exe_ctx, + RegisterContext *reg_ctx, + const lldb_private::ArchSpec &arch, + lldb::RegisterKind reg_kind); }; class GDBRemoteRegisterContext : public RegisterContext Index: source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -20,6 +20,10 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" +#include "lldb/Core/Module.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Core/dwarf.h" +#include "lldb/Core/Value.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" @@ -89,7 +93,17 @@ const RegisterInfo * GDBRemoteRegisterContext::GetRegisterInfoAtIndex (size_t reg) { - return m_reg_info.GetRegisterInfoAtIndex (reg); + ExecutionContext exe_ctx (CalculateThread()); + const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); + RegisterInfo* reg_info = const_cast(m_reg_info.GetRegisterInfoAtIndex (reg)); + if(reg_info->dynamic_size) + { + if (! (m_reg_info.UpdateDynamicRegisterSize (&exe_ctx, this, arch, eRegisterKindDWARF))) + reg_info->byte_size = 4; + else + reg_info->byte_size = 8; + } + return const_cast(reg_info); } size_t @@ -939,6 +953,51 @@ return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num); } +bool +GDBRemoteDynamicRegisterInfo::UpdateDynamicRegisterSize (ExecutionContext *exe_ctx, + RegisterContext *reg_ctx, + const lldb_private::ArchSpec &arch, + lldb::RegisterKind reg_kind) +{ + lldb_private::ConstString sr_reg_name("sr"); + lldb_private::RegisterInfo *reg_info = GetRegisterInfo (sr_reg_name); + uint8_t sr_reg_num = reg_info->kinds[reg_kind]; + lldb_private::ConstString config_reg_name("config5"); + reg_info = GetRegisterInfo (config_reg_name); + uint8_t config5_reg_num = reg_info->kinds[reg_kind]; + + // In MIPS, the floating point registers size is depends on FR and FRE bit. + // if SR.26 ^ config5.8 == 1 then all floating point registers are 64 bits. + // else they are all 32 bits. + const uint8_t dwarf_opcode [] = { + llvm::dwarf::DW_OP_regx, sr_reg_num, llvm::dwarf::DW_OP_lit1, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, + llvm::dwarf::DW_OP_regx, config5_reg_num, llvm::dwarf::DW_OP_lit1, + llvm::dwarf::DW_OP_lit8, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, + llvm::dwarf::DW_OP_lit18, llvm::dwarf::DW_OP_shl, + llvm::dwarf::DW_OP_xor + }; + + + uint32_t addr_size = arch.GetAddressByteSize (); + DataExtractor dwarf_data (dwarf_opcode, sizeof(dwarf_opcode), arch.GetByteOrder (), + addr_size); + ModuleSP opcode_ctx; + DWARFExpression dwarf_expr (opcode_ctx, dwarf_data, nullptr, 0,sizeof(dwarf_opcode)); + Value result; + Error error; + const lldb::offset_t offset = 0; + if(dwarf_expr.Evaluate (exe_ctx, nullptr, nullptr, reg_ctx, opcode_ctx, dwarf_data, nullptr, + offset, sizeof(dwarf_opcode), reg_kind, nullptr, nullptr, result, &error)) + { + return result.GetScalar().UInt(1); + } + else + { + printf("Error executing DwarfExpression::Evaluate %s\n", error.AsCString()); + return true; + } +} void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -553,7 +553,8 @@ reg_num // native register number }, NULL, - NULL + NULL, + 0 // dynamic_size default value }; while (response.GetNameColonValue(name, value)) @@ -638,6 +639,10 @@ { SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16); } + else if (name.compare("dynamic_size") == 0) + { + reg_info.dynamic_size = 1; + } } reg_info.byte_offset = reg_offset;