summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins')
-rw-r--r--lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp103
-rw-r--r--lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h6
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp104
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h3
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp10
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp3
6 files changed, 208 insertions, 21 deletions
diff --git a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
index 09bbcbd9c9f..c32ac930b5a 100644
--- a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
+++ b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp
@@ -410,6 +410,9 @@ EmulateInstructionMIPS64::GetOpcodeForInstruction (const char *op_name)
{ "SD", &EmulateInstructionMIPS64::Emulate_SD, "SD rt,offset(rs)" },
{ "LD", &EmulateInstructionMIPS64::Emulate_LD, "LD rt,offset(base)" },
+ { "SW", &EmulateInstructionMIPS64::Emulate_SW, "SW rt,offset(rs)" },
+ { "LW", &EmulateInstructionMIPS64::Emulate_LW, "LW rt,offset(rs)" },
+
//----------------------------------------------------------------------
// Branch instructions
//----------------------------------------------------------------------
@@ -657,35 +660,95 @@ EmulateInstructionMIPS64::Emulate_DADDiu (llvm::MCInst& insn)
}
bool
+EmulateInstructionMIPS64::Emulate_SW (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t base;
+ int64_t imm, address;
+ Context bad_vaddr_context;
+
+ base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ imm = insn.getOperand(2).getImm();
+
+ RegisterInfo reg_info_base;
+ if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base))
+ return false;
+
+ /* read base register */
+ address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success);
+ if (!success)
+ return false;
+
+ /* destination address */
+ address = address + imm;
+
+ /* Set the bad_vaddr register with base address used in the instruction */
+ bad_vaddr_context.type = eContextInvalid;
+ WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, gcc_dwarf_bad_mips64, address);
+
+ return true;
+}
+
+bool
+EmulateInstructionMIPS64::Emulate_LW (llvm::MCInst& insn)
+{
+ bool success = false;
+ uint32_t base;
+ int64_t imm, address;
+ Context bad_vaddr_context;
+
+ base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
+ imm = insn.getOperand(2).getImm();
+
+ RegisterInfo reg_info_base;
+ if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base))
+ return false;
+
+ /* read base register */
+ address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success);
+ if (!success)
+ return false;
+
+ /* destination address */
+ address = address + imm;
+
+ /* Set the bad_vaddr register with base address used in the instruction */
+ bad_vaddr_context.type = eContextInvalid;
+ WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, gcc_dwarf_bad_mips64, address);
+
+ return true;
+}
+
+bool
EmulateInstructionMIPS64::Emulate_SD (llvm::MCInst& insn)
{
+ uint64_t address;
+ RegisterInfo reg_info_base;
+ RegisterInfo reg_info_src;
bool success = false;
uint32_t imm16 = insn.getOperand(2).getImm();
uint64_t imm = SignedBits(imm16, 15, 0);
uint32_t src, base;
+ Context bad_vaddr_context;
src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg());
base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg());
- /* We look for sp based non-volatile register stores */
- if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src))
- {
- uint64_t address;
- RegisterInfo reg_info_base;
- RegisterInfo reg_info_src;
-
- if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base)
- || !GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src))
- return false;
+ if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base)
+ || !GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src))
+ return false;
- /* read SP */
- address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success);
- if (!success)
- return false;
+ /* read SP */
+ address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success);
+ if (!success)
+ return false;
- /* destination address */
- address = address + imm;
+ /* destination address */
+ address = address + imm;
+ /* We look for sp based non-volatile register stores */
+ if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src))
+ {
Context context;
RegisterValue data_src;
context.type = eContextPushRegisterOnStack;
@@ -702,11 +765,13 @@ EmulateInstructionMIPS64::Emulate_SD (llvm::MCInst& insn)
if (!WriteMemory (context, address, buffer, reg_info_src.byte_size))
return false;
-
- return true;
}
- return false;
+ /* Set the bad_vaddr register with base address used in the instruction */
+ bad_vaddr_context.type = eContextInvalid;
+ WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, gcc_dwarf_bad_mips64, address);
+
+ return true;
}
bool
diff --git a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
index 178417c196f..faefd329a8e 100644
--- a/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
+++ b/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h
@@ -128,6 +128,12 @@ protected:
Emulate_SD (llvm::MCInst& insn);
bool
+ Emulate_SW (llvm::MCInst& insn);
+
+ bool
+ Emulate_LW (llvm::MCInst& insn);
+
+ bool
Emulate_LD (llvm::MCInst& insn);
bool
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
index 917f1351563..6a4dfc08239 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
@@ -20,7 +20,9 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Host/HostInfo.h"
-
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private-enumerations.h"
#include "Plugins/Process/Linux/NativeProcessLinux.h"
#include "Plugins/Process/Linux/Procfs.h"
#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h"
@@ -997,6 +999,106 @@ NativeRegisterContextLinux_mips64::GetWatchpointAddress (uint32_t wp_index)
return hw_addr_map[wp_index];
}
+struct EmulatorBaton
+{
+ lldb::addr_t m_watch_hit_addr;
+ NativeProcessLinux* m_process;
+ NativeRegisterContext* m_reg_context;
+
+ EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) :
+ m_watch_hit_addr(LLDB_INVALID_ADDRESS),
+ m_process(process),
+ m_reg_context(reg_context)
+ {}
+};
+
+static size_t
+ReadMemoryCallback (EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context, lldb::addr_t addr,
+ void *dst, size_t length)
+{
+ size_t bytes_read;
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+ emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read);
+ return bytes_read;
+}
+
+static size_t
+WriteMemoryCallback (EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr, const void *dst, size_t length)
+{
+ return length;
+}
+
+static bool
+ReadRegisterCallback (EmulateInstruction *instruction, void *baton,
+ const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+
+ const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo(
+ lldb::eRegisterKindDWARF, reg_info->kinds[lldb::eRegisterKindDWARF]);
+
+ Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
+ if (error.Success())
+ return true;
+
+ return false;
+}
+
+static bool
+WriteRegisterCallback (EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (reg_info->kinds[lldb::eRegisterKindDWARF] == gcc_dwarf_bad_mips64)
+ {
+ EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton);
+ emulator_baton->m_watch_hit_addr = reg_value.GetAsUInt64 ();
+ }
+
+ return true;
+}
+
+/*
+ * MIPS Linux kernel returns a masked address (last 3bits are masked)
+ * when a HW watchpoint is hit. However user may not have set a watchpoint
+ * on this address. Emulate instruction at PC and find the base address of
+ * the load/store instruction. This will give the exact address used to
+ * read/write the variable. Send this exact address to client so that
+ * it can decide to stop or continue the thread.
+*/
+lldb::addr_t
+NativeRegisterContextLinux_mips64::GetWatchpointHitAddress (uint32_t wp_index)
+{
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+
+ lldb_private::ArchSpec arch;
+ arch = GetRegisterInfoInterface().GetTargetArchitecture();
+ std::unique_ptr<EmulateInstruction> emulator_ap(
+ EmulateInstruction::FindPlugin(arch, lldb_private::eInstructionTypeAny, nullptr));
+
+ if (emulator_ap == nullptr)
+ return LLDB_INVALID_ADDRESS;
+
+ EmulatorBaton baton(static_cast<NativeProcessLinux*>(m_thread.GetProcess().get()), this);
+ emulator_ap->SetBaton (&baton);
+ emulator_ap->SetReadMemCallback (&ReadMemoryCallback);
+ emulator_ap->SetReadRegCallback (&ReadRegisterCallback);
+ emulator_ap->SetWriteMemCallback (&WriteMemoryCallback);
+ emulator_ap->SetWriteRegCallback (&WriteRegisterCallback);
+
+ if (!emulator_ap->ReadInstruction())
+ return LLDB_INVALID_ADDRESS;
+
+ if (emulator_ap->EvaluateInstruction(lldb::eEmulateInstructionOptionNone))
+ return baton.m_watch_hit_addr;
+
+ return LLDB_INVALID_ADDRESS;
+}
+
uint32_t
NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints ()
{
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
index 9a2e89f5bf2..18261875c07 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
@@ -36,6 +36,9 @@ namespace process_linux {
lldb::addr_t
GetPCfromBreakpointLocation (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS) override;
+ lldb::addr_t
+ GetWatchpointHitAddress (uint32_t wp_index) override;
+
const RegisterSet *
GetRegisterSet (uint32_t set_index) const override;
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index 481127a65b1..18f0e6b2972 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -333,6 +333,16 @@ NativeThreadLinux::SetStoppedByWatchpoint (uint32_t wp_index)
std::ostringstream ostr;
ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " ";
ostr << wp_index;
+
+ /*
+ * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For example:
+ * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at 'm', then
+ * watch exception is generated even when 'n' is read/written. To handle this case,
+ * find the base address of the load/store instruction and append it in the stop-info
+ * packet.
+ */
+ ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index);
+
m_stop_description = ostr.str();
m_stop_info.reason = StopReason::eStopReasonWatchpoint;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index f6236f03b8a..4a9e285d2c2 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2020,6 +2020,7 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
StringExtractor desc_extractor(description.c_str());
addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
+ addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
if (wp_addr != LLDB_INVALID_ADDRESS)
{
@@ -2035,7 +2036,7 @@ ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS));
if (log) log->Printf ("failed to find watchpoint");
}
- thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id, wp_hit_addr));
handled = true;
}
else if (reason.compare("exception") == 0)
OpenPOWER on IntegriCloud