[Lldb-commits] [lldb] r181341 - Add watchpoint support for Linux on 64-bit host.
Matt Kopec
Matt.Kopec at intel.com
Tue May 7 12:29:28 PDT 2013
Author: mkopec
Date: Tue May 7 14:29:28 2013
New Revision: 181341
URL: http://llvm.org/viewvc/llvm-project?rev=181341&view=rev
Log:
Add watchpoint support for Linux on 64-bit host.
Modified:
lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp
lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h
lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp
lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h
lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py
lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py
lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py
lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py
lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py
lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py
lldb/trunk/test/lldbtest.py
lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py
lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py
lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py
lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py
Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Tue May 7 14:29:28 2013
@@ -47,6 +47,11 @@
#define PTRACE_SETREGSET 0x4205
#endif
+// Support hardware breakpoints in case it has not been defined
+#ifndef TRAP_HWBKPT
+ #define TRAP_HWBKPT 4
+#endif
+
using namespace lldb_private;
// FIXME: this code is host-dependent with respect to types and
@@ -1415,6 +1420,10 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMo
case TRAP_BRKPT:
message = ProcessMessage::Break(pid);
break;
+
+ case TRAP_HWBKPT:
+ message = ProcessMessage::Watch(pid, (lldb::addr_t)info->si_addr);
+ break;
}
return message;
Modified: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.cpp Tue May 7 14:29:28 2013
@@ -15,6 +15,7 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Host/Host.h"
#include "lldb/Target/Process.h"
@@ -229,6 +230,10 @@ POSIXThread::Notify(const ProcessMessage
BreakNotify(message);
break;
+ case ProcessMessage::eWatchpointMessage:
+ WatchNotify(message);
+ break;
+
case ProcessMessage::eCrashMessage:
CrashNotify(message);
break;
@@ -239,6 +244,58 @@ POSIXThread::Notify(const ProcessMessage
}
}
+bool
+POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool result = false;
+ if (wp)
+ {
+ addr_t wp_addr = wp->GetLoadAddress();
+ size_t wp_size = wp->GetByteSize();
+ bool wp_read = wp->WatchpointRead();
+ bool wp_write = wp->WatchpointWrite();
+ uint32_t wp_hw_index;
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ {
+ wp_hw_index = reg_ctx_sp->SetHardwareWatchpoint(wp_addr, wp_size,
+ wp_read, wp_write);
+ if (wp_hw_index != LLDB_INVALID_INDEX32)
+ {
+ wp->SetHardwareIndex(wp_hw_index);
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+
+bool
+POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool result = false;
+ if (wp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ {
+ result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ if (result == true)
+ wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
+ }
+ }
+ return result;
+}
+
+uint32_t
+POSIXThread::NumSupportedHardwareWatchpoints()
+{
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
void
POSIXThread::BreakNotify(const ProcessMessage &message)
{
@@ -260,12 +317,50 @@ POSIXThread::BreakNotify(const ProcessMe
lldb::break_id_t bp_id = bp_site->GetID();
assert(bp_site && bp_site->ValidForThisThread(this));
-
m_breakpoint = bp_site;
SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
}
void
+POSIXThread::WatchNotify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ lldb::addr_t halt_addr = message.GetHWAddress();
+ if (log)
+ log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8"
+ PRIx64, __FUNCTION__, halt_addr);
+
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointHit(wp_idx))
+ {
+ // Clear the watchpoint hit here
+ reg_ctx->ClearWatchpointHits();
+ break;
+ }
+ }
+
+ if (wp_idx == num_hw_wps)
+ return;
+
+ Target &target = GetProcess()->GetTarget();
+ lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
+
+ if (wp_sp)
+ SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this,
+ wp_sp->GetID()));
+ }
+}
+
+void
POSIXThread::TraceNotify(const ProcessMessage &message)
{
SetStopInfo (StopInfo::CreateStopReasonToTrace(*this));
Modified: lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/POSIXThread.h Tue May 7 14:29:28 2013
@@ -69,6 +69,15 @@ public:
void Notify(const ProcessMessage &message);
+ //--------------------------------------------------------------------------
+ // These methods provide an interface to watchpoints
+ //
+ bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ uint32_t NumSupportedHardwareWatchpoints();
+
private:
RegisterContextPOSIX *
GetRegisterContextPOSIX ()
@@ -92,6 +101,7 @@ private:
GetPrivateStopReason();
void BreakNotify(const ProcessMessage &message);
+ void WatchNotify(const ProcessMessage &message);
void TraceNotify(const ProcessMessage &message);
void LimboNotify(const ProcessMessage &message);
void SignalNotify(const ProcessMessage &message);
Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.cpp Tue May 7 14:29:28 2013
@@ -221,6 +221,9 @@ ProcessMessage::PrintKind(Kind kind)
case eBreakpointMessage:
str = "eBreakpointMessage";
break;
+ case eWatchpointMessage:
+ str = "eWatchpointMessage";
+ break;
case eCrashMessage:
str = "eCrashMessage";
break;
Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessMessage.h Tue May 7 14:29:28 2013
@@ -29,6 +29,7 @@ public:
eSignalDeliveredMessage,
eTraceMessage,
eBreakpointMessage,
+ eWatchpointMessage,
eCrashMessage,
eNewThreadMessage
};
@@ -104,6 +105,10 @@ public:
return ProcessMessage(tid, eBreakpointMessage);
}
+ static ProcessMessage Watch(lldb::tid_t tid, lldb::addr_t wp_addr) {
+ return ProcessMessage(tid, eWatchpointMessage, 0, wp_addr);
+ }
+
/// Indicates that the thread @p tid crashed.
static ProcessMessage Crash(lldb::pid_t pid, CrashReason reason,
int signo, lldb::addr_t fault_addr) {
@@ -143,6 +148,11 @@ public:
return m_addr;
}
+ lldb::addr_t GetHWAddress() const {
+ assert(GetKind() == eWatchpointMessage);
+ return m_addr;
+ }
+
lldb::tid_t GetChildTID() const {
assert(GetKind() == eNewThreadMessage);
return m_child_tid;
Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Tue May 7 14:29:28 2013
@@ -14,6 +14,7 @@
// C++ Includes
// Other libraries and framework includes
+#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
@@ -364,6 +365,7 @@ ProcessPOSIX::SendMessage(const ProcessM
case ProcessMessage::eTraceMessage:
case ProcessMessage::eBreakpointMessage:
+ case ProcessMessage::eWatchpointMessage:
SetPrivateState(eStateStopped);
break;
@@ -546,6 +548,132 @@ ProcessPOSIX::DisableBreakpointSite(Brea
return DisableSoftwareBreakpoint(bp_site);
}
+Error
+ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+ watchID, (uint64_t)addr);
+ return error;
+ }
+
+ bool wp_enabled = true;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_enabled &= thread->EnableHardwareWatchpoint(wp);
+ else
+ {
+ wp_enabled = false;
+ break;
+ }
+ }
+ if (wp_enabled)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ {
+ // Watchpoint enabling failed on at least one
+ // of the threads so roll back all of them
+ DisableWatchpoint(wp, false);
+ error.SetErrorString("Setting hardware watchpoint failed");
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.",
+ watchID, (uint64_t)addr);
+ // This is needed (for now) to keep watchpoints disabled correctly
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ bool wp_disabled = true;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_disabled &= thread->DisableHardwareWatchpoint(wp);
+ else
+ wp_disabled = false;
+ }
+ if (wp_disabled)
+ {
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("Disabling hardware watchpoint failed");
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num)
+{
+ Error error;
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+ if (thread)
+ num = thread->NumSupportedHardwareWatchpoints();
+ else
+ error.SetErrorString("Process does not exist.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after)
+{
+ Error error = GetWatchpointSupportInfo(num);
+ // Watchpoints trigger and halt the inferior after
+ // the corresponding instruction has been executed.
+ after = true;
+ return error;
+}
+
uint32_t
ProcessPOSIX::UpdateThreadListIfNeeded()
{
Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h Tue May 7 14:29:28 2013
@@ -108,6 +108,18 @@ public:
virtual lldb_private::Error
DisableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+ virtual lldb_private::Error
+ EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num, bool &after);
+
virtual uint32_t
UpdateThreadListIfNeeded();
Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp Tue May 7 14:29:28 2013
@@ -25,6 +25,15 @@ do {
m_register_infos[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \
} while(false);
+#define DR_OFFSET(reg_index) \
+ (offsetof(UserArea, u_debugreg[reg_index]))
+
+#define UPDATE_DR_INFO(reg_index) \
+do { \
+ m_register_infos[dr##reg_index].byte_size = sizeof(UserArea::u_debugreg[0]); \
+ m_register_infos[dr##reg_index].byte_offset = DR_OFFSET(reg_index); \
+} while(false);
+
typedef struct _GPR
{
uint64_t r15;
@@ -155,5 +164,14 @@ RegisterContextLinux_x86_64::UpdateRegis
UPDATE_I386_GPR_INFO(esp, rsp);
UPDATE_I386_GPR_INFO(eip, rip);
UPDATE_I386_GPR_INFO(eflags, rflags);
+
+ UPDATE_DR_INFO(0);
+ UPDATE_DR_INFO(1);
+ UPDATE_DR_INFO(2);
+ UPDATE_DR_INFO(3);
+ UPDATE_DR_INFO(4);
+ UPDATE_DR_INFO(5);
+ UPDATE_DR_INFO(6);
+ UPDATE_DR_INFO(7);
}
Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContextPOSIX.h Tue May 7 14:29:28 2013
@@ -35,6 +35,20 @@ public:
/// @return
/// True if the operation succeeded and false otherwise.
virtual bool UpdateAfterBreakpoint() { return true; }
+
+ // Checks to see if a watchpoint specified by hw_index caused the inferior
+ // to stop.
+ virtual bool
+ IsWatchpointHit (uint32_t hw_index) { return false; }
+
+ // Resets any watchpoints that have been hit.
+ virtual bool
+ ClearWatchpointHits () { return false; }
+
+ // Returns the watchpoint address associated with a watchpoint hardware
+ // index.
+ virtual lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index) {return LLDB_INVALID_ADDRESS; }
};
#endif // #ifndef liblldb_RegisterContextPOSIX_H_
Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp Tue May 7 14:29:28 2013
@@ -340,6 +340,11 @@ g_reg_sets[k_num_register_sets] =
{ gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+#define DEFINE_DR(reg, i) \
+ { #reg#i, NULL, 0, 0, eEncodingUint, eFormatHex, \
+ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+
#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(RegisterContext_x86_64::FPR))
static RegisterInfo
@@ -439,7 +444,17 @@ g_register_infos[k_num_registers] =
DEFINE_YMM(ymm, 12),
DEFINE_YMM(ymm, 13),
DEFINE_YMM(ymm, 14),
- DEFINE_YMM(ymm, 15)
+ DEFINE_YMM(ymm, 15),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0),
+ DEFINE_DR(dr, 1),
+ DEFINE_DR(dr, 2),
+ DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4),
+ DEFINE_DR(dr, 5),
+ DEFINE_DR(dr, 6),
+ DEFINE_DR(dr, 7)
};
RegisterInfo *RegisterContext_x86_64::m_register_infos = g_register_infos;
@@ -869,6 +884,27 @@ RegisterContext_x86_64::WriteAllRegister
}
bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ value);
+}
+
+bool
RegisterContext_x86_64::UpdateAfterBreakpoint()
{
// PC points one byte past the int3 responsible for the breakpoint.
@@ -1178,6 +1214,183 @@ RegisterContext_x86_64::ConvertRegisterK
return LLDB_INVALID_REGNUM;
}
+uint32_t
+RegisterContext_x86_64::NumSupportedHardwareWatchpoints()
+{
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointVacant(uint32_t hw_index)
+{
+ bool is_vacant = false;
+ RegisterValue value;
+
+ if (ReadRegister(dr7, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_vacant = (val & (3 << 2*hw_index)) == 0;
+ }
+
+ return is_vacant;
+}
+
+static uint32_t
+size_and_rw_bits(size_t size, bool read, bool write)
+{
+ uint32_t rw;
+ if (read) {
+ rw = 0x3; // READ or READ/WRITE
+ } else if (write) {
+ rw = 0x1; // WRITE
+ } else {
+ assert(0 && "read and write cannot both be false");
+ }
+
+ switch (size) {
+ case 1:
+ return rw;
+ case 2:
+ return (0x1 << 2) | rw;
+ case 4:
+ return (0x3 << 2) | rw;
+ case 8:
+ return (0x2 << 2) | rw;
+ default:
+ assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
+ }
+}
+
+uint32_t
+RegisterContext_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ if (num_hw_watchpoints == 0)
+ return LLDB_INVALID_INDEX32;
+
+ if (!(size == 1 || size == 2 || size == 4 || size == 8))
+ return LLDB_INVALID_INDEX32;
+
+ if (read == false && write == false)
+ return LLDB_INVALID_INDEX32;
+
+ uint32_t hw_index = 0;
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ break;
+ }
+
+ // Set both dr7 (debug control register) and dri (debug address register).
+
+ // dr7{7-0} encodes the local/gloabl enable bits:
+ // global enable --. .-- local enable
+ // | |
+ // v v
+ // dr0 -> bits{1-0}
+ // dr1 -> bits{3-2}
+ // dr2 -> bits{5-4}
+ // dr3 -> bits{7-6}
+ //
+ // dr7{31-16} encodes the rw/len bits:
+ // b_x+3, b_x+2, b_x+1, b_x
+ // where bits{x+1, x} => rw
+ // 0b00: execute, 0b01: write, 0b11: read-or-write,
+ // 0b10: io read-or-write (unused)
+ // and bits{x+3, x+2} => len
+ // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
+ //
+ // dr0 -> bits{19-16}
+ // dr1 -> bits{23-20}
+ // dr2 -> bits{27-24}
+ // dr3 -> bits{31-28}
+ if (hw_index < num_hw_watchpoints)
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() |
+ (1 << (2*hw_index) |
+ size_and_rw_bits(size, read, write) <<
+ (16+4*hw_index));
+
+ if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) &&
+ WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return hw_index;
+ }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext_x86_64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index));
+
+ if (WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointHit(uint32_t hw_index)
+{
+ bool is_hit = false;
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr6, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_hit = val & (1 << hw_index);
+ }
+ }
+
+ return is_hit;
+}
+
+addr_t
+RegisterContext_x86_64::GetWatchpointAddress(uint32_t hw_index)
+{
+ addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS;
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ if (!IsWatchpointVacant(hw_index))
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr0 + hw_index, value))
+ wp_monitor_addr = value.GetAsUInt64();
+ }
+ }
+
+ return wp_monitor_addr;
+}
+
+
+bool
+RegisterContext_x86_64::ClearWatchpointHits()
+{
+ return WriteRegister(dr6, RegisterValue((uint64_t)0));
+}
+
bool
RegisterContext_x86_64::HardwareSingleStep(bool enable)
{
Modified: lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/RegisterContext_x86_64.h Tue May 7 14:29:28 2013
@@ -110,6 +110,15 @@ enum
fpu_ymm15,
k_last_avx = fpu_ymm15,
+ dr0,
+ dr1,
+ dr2,
+ dr3,
+ dr4,
+ dr5,
+ dr6,
+ dr7,
+
k_num_registers,
k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
k_num_fpr_registers = k_last_fpr - k_first_fpr + 1,
@@ -175,15 +184,37 @@ public:
uint32_t
ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
bool
HardwareSingleStep(bool enable);
bool
UpdateAfterBreakpoint();
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ IsWatchpointHit (uint32_t hw_index);
+
+ lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
//---------------------------------------------------------------------------
// Generic floating-point registers
//---------------------------------------------------------------------------
+
struct MMSReg
{
uint8_t bytes[10];
@@ -280,6 +311,12 @@ protected:
virtual const lldb_private::RegisterInfo *
GetRegisterInfo();
+ virtual bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
private:
static lldb_private::RegisterInfo *m_register_infos;
Modified: lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py Tue May 7 14:29:28 2013
@@ -22,7 +22,6 @@ class HelloWatchpointTestCase(TestBase):
self.setTearDownCleanup(dictionary=self.d)
self.hello_watchpoint()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_hello_watchpoint_with_dwarf_using_watchpoint_set(self):
"""Test a simple sequence of watchpoint creation and watchpoint hit."""
Modified: lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/variable_out_of_scope/TestWatchedVarHitWhenInScope.py Tue May 7 14:29:28 2013
@@ -20,7 +20,7 @@ class WatchedVariableHitWhenInScopeTestC
# clearer API to express this.
#
- @unittest2.expectedFailure
+ @expectedFailureDarwin
@dsym_test
def test_watched_var_should_only_hit_when_in_scope_with_dsym(self):
"""Test that a variable watchpoint should only hit when in scope."""
@@ -28,7 +28,7 @@ class WatchedVariableHitWhenInScopeTestC
self.setTearDownCleanup(dictionary=self.d)
self.watched_var()
- @unittest2.expectedFailure
+ @expectedFailureDarwin
@dwarf_test
def test_watched_var_should_only_hit_when_in_scope_with_dwarf(self):
"""Test that a variable watchpoint should only hit when in scope."""
Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/TestWatchpointCommands.py Tue May 7 14:29:28 2013
@@ -34,7 +34,6 @@ class WatchpointCommandsTestCase(TestBas
self.setTearDownCleanup(dictionary=self.d)
self.normal_read_write_watchpoint()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_rw_watchpoint_with_dwarf(self):
"""Test read_write watchpoint and expect to stop two times."""
@@ -50,7 +49,6 @@ class WatchpointCommandsTestCase(TestBas
self.setTearDownCleanup(dictionary=self.d)
self.delete_read_write_watchpoint()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_rw_watchpoint_delete_with_dwarf(self):
"""Test delete watchpoint and expect not to stop for watchpoint."""
@@ -66,7 +64,6 @@ class WatchpointCommandsTestCase(TestBas
self.setTearDownCleanup(dictionary=self.d)
self.ignore_read_write_watchpoint()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_rw_watchpoint_set_ignore_count_with_dwarf(self):
"""Test watchpoint ignore count and expect to not to stop at all."""
@@ -82,7 +79,6 @@ class WatchpointCommandsTestCase(TestBas
self.setTearDownCleanup(dictionary=self.d)
self.read_write_watchpoint_disable_after_first_stop()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_rw_disable_after_first_stop__with_dwarf(self):
"""Test read_write watchpoint but disable it after the first stop."""
@@ -98,7 +94,6 @@ class WatchpointCommandsTestCase(TestBas
self.setTearDownCleanup(dictionary=self.d)
self.read_write_watchpoint_disable_then_enable()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_rw_disable_then_enable_with_dwarf(self):
"""Test read_write watchpoint, disable initially, then enable it."""
Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py Tue May 7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointLLDBCommandTestCase(Test
self.setTearDownCleanup(dictionary=self.d)
self.watchpoint_command()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_watchpoint_command_with_dwarf(self):
"""Test 'watchpoint command'."""
@@ -49,7 +48,6 @@ class WatchpointLLDBCommandTestCase(Test
self.setTearDownCleanup(dictionary=self.d)
self.watchpoint_command_can_disable_a_watchpoint()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_watchpoint_command_can_disable_a_watchpoint_with_dwarf(self):
"""Test that 'watchpoint command' action can disable a watchpoint after it is triggered."""
Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py Tue May 7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointPythonCommandTestCase(Te
self.setTearDownCleanup(dictionary=self.d)
self.watchpoint_command()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_watchpoint_command_with_dwarf(self):
"""Test 'watchpoint command'."""
Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_commands/condition/TestWatchpointConditionCmd.py Tue May 7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointConditionCmdTestCase(Tes
self.setTearDownCleanup(dictionary=self.d)
self.watchpoint_condition()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_watchpoint_cond_with_dwarf(self):
"""Test watchpoint condition."""
Modified: lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py (original)
+++ lldb/trunk/test/functionalities/watchpoint/watchpoint_events/TestWatchpointEvents.py Tue May 7 14:29:28 2013
@@ -18,7 +18,6 @@ class TestWatchpointEvents (TestBase):
self.buildDsym()
self.step_over_stepping()
- @expectedFailureLinux # bugzilla 14437
@python_api_test
@dwarf_test
def test_with_dwarf_and_python_api(self):
Modified: lldb/trunk/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/lldbtest.py (original)
+++ lldb/trunk/test/lldbtest.py Tue May 7 14:29:28 2013
@@ -549,6 +549,42 @@ def expectedFailureLinux(bugnumber=None)
return wrapper
return expectedFailureLinux_impl
+def expectedFailureDarwin(bugnumber=None):
+ if callable(bugnumber):
+ @wraps(bugnumber)
+ def expectedFailureDarwin_easy_wrapper(*args, **kwargs):
+ from unittest2 import case
+ self = args[0]
+ platform = sys.platform
+ try:
+ bugnumber(*args, **kwargs)
+ except Exception:
+ if "darwin" in platform:
+ raise case._ExpectedFailure(sys.exc_info(),None)
+ else:
+ raise
+ if "darwin" in platform:
+ raise case._UnexpectedSuccess(sys.exc_info(),None)
+ return expectedFailureDarwin_easy_wrapper
+ else:
+ def expectedFailureDarwin_impl(func):
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ from unittest2 import case
+ self = args[0]
+ platform = sys.platform
+ try:
+ func(*args, **kwargs)
+ except Exception:
+ if "darwin" in platform:
+ raise case._ExpectedFailure(sys.exc_info(),bugnumber)
+ else:
+ raise
+ if "darwin" in platform:
+ raise case._UnexpectedSuccess(sys.exc_info(),bugnumber)
+ return wrapper
+ return expectedFailureDarwin_impl
+
def skipOnLinux(func):
"""Decorate the item to skip tests that should be skipped on Linux."""
if isinstance(func, type) and issubclass(func, unittest2.TestCase):
Modified: lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py (original)
+++ lldb/trunk/test/python_api/watchpoint/TestSetWatchpoint.py Tue May 7 14:29:28 2013
@@ -28,7 +28,6 @@ class SetWatchpointAPITestCase(TestBase)
self.buildDsym()
self.do_set_watchpoint()
- @expectedFailureLinux # bugzilla 14416
@python_api_test
@dwarf_test
def test_watch_val_with_dwarf(self):
Modified: lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py (original)
+++ lldb/trunk/test/python_api/watchpoint/TestWatchpointIgnoreCount.py Tue May 7 14:29:28 2013
@@ -28,7 +28,6 @@ class WatchpointIgnoreCountTestCase(Test
self.buildDsym()
self.do_watchpoint_ignore_count()
- @expectedFailureLinux # bugzilla 14416
@python_api_test
@dwarf_test
def test_set_watch_ignore_count_with_dwarf(self):
Modified: lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py (original)
+++ lldb/trunk/test/python_api/watchpoint/TestWatchpointIter.py Tue May 7 14:29:28 2013
@@ -28,7 +28,6 @@ class WatchpointIteratorTestCase(TestBas
self.buildDsym()
self.do_watchpoint_iter()
- @expectedFailureLinux # bugzilla 14416
@python_api_test
@dwarf_test
def test_watch_iter_with_dwarf(self):
Modified: lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py?rev=181341&r1=181340&r2=181341&view=diff
==============================================================================
--- lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py (original)
+++ lldb/trunk/test/python_api/watchpoint/condition/TestWatchpointConditionAPI.py Tue May 7 14:29:28 2013
@@ -33,7 +33,6 @@ class WatchpointConditionAPITestCase(Tes
self.setTearDownCleanup(dictionary=self.d)
self.watchpoint_condition_api()
- @expectedFailureLinux # bugzilla 14416
@dwarf_test
def test_watchpoint_cond_api_with_dwarf(self):
"""Test watchpoint condition API."""
More information about the lldb-commits
mailing list