[LLDB][MIPS] MIPS32 branch emulation and single-stepping

SUMMARY:
    This patch implements
      1. Emulation of MIPS32 branch instructions
      2. Enable single-stepping for MIPS32 instructions
      3. Correction in emulation of MIPS64 branch instructions with delay slot
      4. Adjust breakpoint address when breakpoint is hit in a forbidden slot of compact branch instruction
    
    Reviewers: clayborg
    Subscribers: mohit.bhakkad, sagar, bhushan, lldb-commits, emaste, nitesh.jain
    Differential Revision: http://reviews.llvm.org/D10596

llvm-svn: 240373
This commit is contained in:
Jaydeep Patil 2015-06-23 03:37:08 +00:00
parent 49943652f5
commit c60c94528c
8 changed files with 2670 additions and 112 deletions

View File

@ -141,6 +141,9 @@ public:
lldb::addr_t
GetPC (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
virtual lldb::addr_t
GetPCfromBreakpointLocation (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
Error
SetPC (lldb::addr_t pc);

View File

@ -143,6 +143,12 @@ NativeRegisterContext::GetPC (lldb::addr_t fail_value)
return retval;
}
lldb::addr_t
NativeRegisterContext::GetPCfromBreakpointLocation (lldb::addr_t fail_value)
{
return GetPC (fail_value);
}
Error
NativeRegisterContext::SetPC (lldb::addr_t pc)
{

File diff suppressed because it is too large Load Diff

View File

@ -130,6 +130,171 @@ protected:
bool
Emulate_LW (llvm::MCInst& insn);
bool
Emulate_BEQ (llvm::MCInst& insn);
bool
Emulate_BNE (llvm::MCInst& insn);
bool
Emulate_BEQL (llvm::MCInst& insn);
bool
Emulate_BNEL (llvm::MCInst& insn);
bool
Emulate_BGEZALL (llvm::MCInst& insn);
bool
Emulate_BAL (llvm::MCInst& insn);
bool
Emulate_BGEZAL (llvm::MCInst& insn);
bool
Emulate_BALC (llvm::MCInst& insn);
bool
Emulate_BC (llvm::MCInst& insn);
bool
Emulate_BGEZ (llvm::MCInst& insn);
bool
Emulate_BLEZALC (llvm::MCInst& insn);
bool
Emulate_BGEZALC (llvm::MCInst& insn);
bool
Emulate_BLTZALC (llvm::MCInst& insn);
bool
Emulate_BGTZALC (llvm::MCInst& insn);
bool
Emulate_BEQZALC (llvm::MCInst& insn);
bool
Emulate_BNEZALC (llvm::MCInst& insn);
bool
Emulate_BEQC (llvm::MCInst& insn);
bool
Emulate_BNEC (llvm::MCInst& insn);
bool
Emulate_BLTC (llvm::MCInst& insn);
bool
Emulate_BGEC (llvm::MCInst& insn);
bool
Emulate_BLTUC (llvm::MCInst& insn);
bool
Emulate_BGEUC (llvm::MCInst& insn);
bool
Emulate_BLTZC (llvm::MCInst& insn);
bool
Emulate_BLEZC (llvm::MCInst& insn);
bool
Emulate_BGEZC (llvm::MCInst& insn);
bool
Emulate_BGTZC (llvm::MCInst& insn);
bool
Emulate_BEQZC (llvm::MCInst& insn);
bool
Emulate_BNEZC (llvm::MCInst& insn);
bool
Emulate_BGEZL (llvm::MCInst& insn);
bool
Emulate_BGTZ (llvm::MCInst& insn);
bool
Emulate_BGTZL (llvm::MCInst& insn);
bool
Emulate_BLEZ (llvm::MCInst& insn);
bool
Emulate_BLEZL (llvm::MCInst& insn);
bool
Emulate_BLTZ (llvm::MCInst& insn);
bool
Emulate_BLTZAL (llvm::MCInst& insn);
bool
Emulate_BLTZALL (llvm::MCInst& insn);
bool
Emulate_BLTZL (llvm::MCInst& insn);
bool
Emulate_BOVC (llvm::MCInst& insn);
bool
Emulate_BNVC (llvm::MCInst& insn);
bool
Emulate_J (llvm::MCInst& insn);
bool
Emulate_JAL (llvm::MCInst& insn);
bool
Emulate_JALR (llvm::MCInst& insn);
bool
Emulate_JIALC (llvm::MCInst& insn);
bool
Emulate_JIC (llvm::MCInst& insn);
bool
Emulate_JR (llvm::MCInst& insn);
bool
Emulate_BC1F (llvm::MCInst& insn);
bool
Emulate_BC1T (llvm::MCInst& insn);
bool
Emulate_BC1FL (llvm::MCInst& insn);
bool
Emulate_BC1TL (llvm::MCInst& insn);
bool
Emulate_BC1EQZ (llvm::MCInst& insn);
bool
Emulate_BC1NEZ (llvm::MCInst& insn);
bool
Emulate_BC1ANY2F (llvm::MCInst& insn);
bool
Emulate_BC1ANY2T (llvm::MCInst& insn);
bool
Emulate_BC1ANY4F (llvm::MCInst& insn);
bool
Emulate_BC1ANY4T (llvm::MCInst& insn);
bool
nonvolatile_reg_p (uint32_t regnum);

View File

@ -758,7 +758,7 @@ EmulateInstructionMIPS64::Emulate_BEQ (llvm::MCInst& insn)
if (rs_val == rt_val)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
context.type = eContextRelativeBranchImmediate;
@ -801,7 +801,7 @@ EmulateInstructionMIPS64::Emulate_BNE (llvm::MCInst& insn)
if (rs_val != rt_val)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
context.type = eContextRelativeBranchImmediate;
@ -913,7 +913,7 @@ EmulateInstructionMIPS64::Emulate_BGEZL (llvm::MCInst& insn)
* PC = PC + sign_ext (offset << 2)
*/
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(2).getImm();
offset = insn.getOperand(1).getImm();
pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
if (!success)
@ -952,7 +952,7 @@ EmulateInstructionMIPS64::Emulate_BLTZL (llvm::MCInst& insn)
* PC = PC + sign_ext (offset << 2)
*/
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(2).getImm();
offset = insn.getOperand(1).getImm();
pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
if (!success)
@ -991,7 +991,7 @@ EmulateInstructionMIPS64::Emulate_BGTZL (llvm::MCInst& insn)
* PC = PC + sign_ext (offset << 2)
*/
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(2).getImm();
offset = insn.getOperand(1).getImm();
pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
if (!success)
@ -1030,7 +1030,7 @@ EmulateInstructionMIPS64::Emulate_BLEZL (llvm::MCInst& insn)
* PC = PC + sign_ext (offset << 2)
*/
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(2).getImm();
offset = insn.getOperand(1).getImm();
pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
if (!success)
@ -1069,7 +1069,7 @@ EmulateInstructionMIPS64::Emulate_BGTZ (llvm::MCInst& insn)
* PC = PC + sign_ext (offset << 2)
*/
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(2).getImm();
offset = insn.getOperand(1).getImm();
pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
if (!success)
@ -1082,7 +1082,7 @@ EmulateInstructionMIPS64::Emulate_BGTZ (llvm::MCInst& insn)
if (rs_val > 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
context.type = eContextRelativeBranchImmediate;
@ -1108,7 +1108,7 @@ EmulateInstructionMIPS64::Emulate_BLEZ (llvm::MCInst& insn)
* PC = PC + sign_ext (offset << 2)
*/
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(2).getImm();
offset = insn.getOperand(1).getImm();
pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
if (!success)
@ -1121,7 +1121,7 @@ EmulateInstructionMIPS64::Emulate_BLEZ (llvm::MCInst& insn)
if (rs_val <= 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
context.type = eContextRelativeBranchImmediate;
@ -1147,7 +1147,7 @@ EmulateInstructionMIPS64::Emulate_BLTZ (llvm::MCInst& insn)
* PC = PC + sign_ext (offset << 2)
*/
rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
offset = insn.getOperand(2).getImm();
offset = insn.getOperand(1).getImm();
pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success);
if (!success)
@ -1160,7 +1160,7 @@ EmulateInstructionMIPS64::Emulate_BLTZ (llvm::MCInst& insn)
if (rs_val < 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
context.type = eContextRelativeBranchImmediate;
@ -1307,7 +1307,7 @@ EmulateInstructionMIPS64::Emulate_BGEZAL (llvm::MCInst& insn)
if ((int64_t) rs_val >= 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
return false;
@ -1350,7 +1350,7 @@ EmulateInstructionMIPS64::Emulate_BLTZAL (llvm::MCInst& insn)
if ((int64_t) rs_val < 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
return false;
@ -1691,7 +1691,7 @@ EmulateInstructionMIPS64::Emulate_BGEZ (llvm::MCInst& insn)
if (rs_val >= 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target))
return false;
@ -2532,7 +2532,7 @@ EmulateInstructionMIPS64::Emulate_BC1F (llvm::MCInst& insn)
if ((fcsr & (1 << cc)) == 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
@ -2573,7 +2573,7 @@ EmulateInstructionMIPS64::Emulate_BC1T (llvm::MCInst& insn)
if ((fcsr & (1 << cc)) != 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
@ -2694,7 +2694,7 @@ EmulateInstructionMIPS64::Emulate_BC1EQZ (llvm::MCInst& insn)
if ((ft_val & 1) == 0)
target = pc + 4 + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
@ -2733,7 +2733,7 @@ EmulateInstructionMIPS64::Emulate_BC1NEZ (llvm::MCInst& insn)
if ((ft_val & 1) != 0)
target = pc + 4 + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
@ -2776,7 +2776,7 @@ EmulateInstructionMIPS64::Emulate_BC1ANY2F (llvm::MCInst& insn)
if (((fcsr >> cc) & 3) != 3)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
@ -2819,7 +2819,7 @@ EmulateInstructionMIPS64::Emulate_BC1ANY2T (llvm::MCInst& insn)
if (((fcsr >> cc) & 3) != 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
@ -2864,7 +2864,7 @@ EmulateInstructionMIPS64::Emulate_BC1ANY4F (llvm::MCInst& insn)
if (((fcsr >> cc) & 0xf) != 0xf)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;
@ -2909,7 +2909,7 @@ EmulateInstructionMIPS64::Emulate_BC1ANY4T (llvm::MCInst& insn)
if (((fcsr >> cc) & 0xf) != 0)
target = pc + offset;
else
target = pc + 4;
target = pc + 8;
Context context;

View File

@ -2018,7 +2018,7 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
{
// If a watchpoint was hit, report it
uint32_t wp_index;
Error error = thread_sp->GetRegisterContext()->GetWatchpointHitIndex(wp_index, NULL);
Error error = thread_sp->GetRegisterContext()->GetWatchpointHitIndex(wp_index, LLDB_INVALID_ADDRESS);
if (error.Fail() && log)
log->Printf("NativeProcessLinux::%s() "
"received error while checking for watchpoint hits, "
@ -2442,7 +2442,9 @@ NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadProtocolSP thread_sp
}
}
else if (m_arch.GetMachine() == llvm::Triple::mips64
|| m_arch.GetMachine() == llvm::Triple::mips64el)
|| m_arch.GetMachine() == llvm::Triple::mips64el
|| m_arch.GetMachine() == llvm::Triple::mips
|| m_arch.GetMachine() == llvm::Triple::mipsel)
error = SetSoftwareBreakpoint(next_pc, 4);
else
{
@ -2462,7 +2464,8 @@ bool
NativeProcessLinux::SupportHardwareSingleStepping() const
{
if (m_arch.GetMachine() == llvm::Triple::arm
|| m_arch.GetMachine() == llvm::Triple::mips64 || m_arch.GetMachine() == llvm::Triple::mips64el)
|| m_arch.GetMachine() == llvm::Triple::mips64 || m_arch.GetMachine() == llvm::Triple::mips64el
|| m_arch.GetMachine() == llvm::Triple::mips || m_arch.GetMachine() == llvm::Triple::mipsel)
return false;
return true;
}
@ -3028,7 +3031,6 @@ NativeProcessLinux::GetSoftwareBreakpointPCOffset (NativeRegisterContextSP conte
// set per architecture. Need ARM, MIPS support here.
static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xd4 };
static const uint8_t g_i386_opcode [] = { 0xCC };
static const uint8_t g_mips64_opcode[] = { 0x00, 0x00, 0x00, 0x0d };
switch (m_arch.GetMachine ())
{
@ -3049,7 +3051,7 @@ NativeProcessLinux::GetSoftwareBreakpointPCOffset (NativeRegisterContextSP conte
case llvm::Triple::mips64el:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
actual_opcode_size = static_cast<uint32_t> (sizeof(g_mips64_opcode));
actual_opcode_size = 0;
return Error ();
default:
@ -3553,7 +3555,7 @@ NativeProcessLinux::FixupBreakpointPCAsNeeded (NativeThreadProtocolSP &thread_sp
}
// First try probing for a breakpoint at a software breakpoint location: PC - breakpoint size.
const lldb::addr_t initial_pc_addr = context_sp->GetPC ();
const lldb::addr_t initial_pc_addr = context_sp->GetPCfromBreakpointLocation ();
lldb::addr_t breakpoint_addr = initial_pc_addr;
if (breakpoint_size > 0)
{

View File

@ -485,6 +485,58 @@ NativeRegisterContextLinux_mips64::GetRegisterSetCount () const
return k_num_register_sets;
}
lldb::addr_t
NativeRegisterContextLinux_mips64::GetPCfromBreakpointLocation (lldb::addr_t fail_value)
{
Error error;
RegisterValue pc_value;
lldb::addr_t pc = fail_value;
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf ("NativeRegisterContextLinux_mips64::%s Reading PC from breakpoint location", __FUNCTION__);
// PC register is at index 34 of the register array
const RegisterInfo *const pc_info_p = GetRegisterInfoAtIndex (34);
error = ReadRegister (pc_info_p, pc_value);
if (error.Success ())
{
pc = pc_value.GetAsUInt64 ();
// CAUSE register is at index 37 of the register array
const RegisterInfo *const cause_info_p = GetRegisterInfoAtIndex (37);
RegisterValue cause_value;
ReadRegister (cause_info_p, cause_value);
uint64_t cause = cause_value.GetAsUInt64 ();
if (log)
log->Printf ("NativeRegisterContextLinux_mips64::%s PC 0x%" PRIx64 " Cause 0x%" PRIx64, __FUNCTION__, pc, cause);
/*
* The breakpoint might be in a delay slot. In this case PC points
* to the delayed branch instruction rather then the instruction
* in the delay slot. If the CAUSE.BD flag is set then adjust the
* PC based on the size of the branch instruction.
*/
if ((cause & (1 << 31)) != 0)
{
lldb::addr_t branch_delay = 0;
branch_delay = 4; // FIXME - Adjust according to size of branch instruction at PC
pc = pc + branch_delay;
pc_value.SetUInt64 (pc);
WriteRegister (pc_info_p, pc_value);
if (log)
log->Printf ("NativeRegisterContextLinux_mips64::%s New PC 0x%" PRIx64, __FUNCTION__, pc);
}
}
return pc;
}
const RegisterSet *
NativeRegisterContextLinux_mips64::GetRegisterSet (uint32_t set_index) const
{

View File

@ -33,6 +33,9 @@ namespace process_linux {
uint32_t
GetRegisterSetCount () const override;
lldb::addr_t
GetPCfromBreakpointLocation (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS) override;
const RegisterSet *
GetRegisterSet (uint32_t set_index) const override;